blob: 90bc107e153712f24719931b7994d6a237686a79 [file] [log] [blame]
// 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/delete_page_task.h"
#include <memory>
#include <vector>
#include "base/bind.h"
#include "base/files/file_util.h"
#include "base/memory/weak_ptr.h"
#include "base/optional.h"
#include "base/strings/utf_string_conversions.h"
#include "base/test/metrics/histogram_tester.h"
#include "base/time/time.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_model_utils.h"
#include "components/offline_pages/core/offline_clock.h"
#include "components/offline_pages/core/offline_page_types.h"
#include "components/offline_pages/core/offline_store_types.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "url/gurl.h"
namespace offline_pages {
using DeletedPageInfo = OfflinePageModel::DeletedPageInfo;
namespace {
const char kTestNamespace[] = "default";
const GURL kTestUrl1("http://example.com");
const GURL kTestUrl2("http://other.page.com");
const int64_t kTestOfflineIdNoMatch = 20170905LL;
const ClientId kTestClientIdNoMatch(kTestNamespace, "20170905");
} // namespace
class DeletePageTaskTest : public ModelTaskTestBase {
public:
DeletePageTaskTest();
~DeletePageTaskTest() override;
void SetUp() override;
void ResetResults();
void OnDeletePageDone(DeletePageResult result,
const std::vector<DeletedPageInfo>& deleted_page_infos);
bool CheckPageDeleted(const OfflinePageItem& page);
DeletePageTask::DeletePageTaskCallback delete_page_callback();
base::HistogramTester* histogram_tester() { return histogram_tester_.get(); }
const base::Optional<DeletePageResult>& last_delete_page_result() {
return last_delete_page_result_;
}
const std::vector<DeletedPageInfo>& last_deleted_page_infos() {
return last_deleted_page_infos_;
}
private:
std::unique_ptr<base::HistogramTester> histogram_tester_;
base::Optional<DeletePageResult> last_delete_page_result_;
std::vector<DeletedPageInfo> last_deleted_page_infos_;
};
DeletePageTaskTest::DeletePageTaskTest() {}
DeletePageTaskTest::~DeletePageTaskTest() {}
void DeletePageTaskTest::SetUp() {
ModelTaskTestBase::SetUp();
histogram_tester_ = std::make_unique<base::HistogramTester>();
}
void DeletePageTaskTest::OnDeletePageDone(
DeletePageResult result,
const std::vector<DeletedPageInfo>& deleted_page_infos) {
last_delete_page_result_ = result;
last_deleted_page_infos_ = deleted_page_infos;
}
DeletePageTask::DeletePageTaskCallback
DeletePageTaskTest::delete_page_callback() {
return base::BindOnce(&DeletePageTaskTest::OnDeletePageDone,
base::AsWeakPtr(this));
}
bool DeletePageTaskTest::CheckPageDeleted(const OfflinePageItem& page) {
auto stored_page = store_test_util()->GetPageByOfflineId(page.offline_id);
return !base::PathExists(page.file_path) && !stored_page;
}
TEST_F(DeletePageTaskTest, DeletePageByOfflineId) {
// Add 3 pages and try to delete 2 of them using offline id.
generator()->SetNamespace(kTestNamespace);
OfflinePageItem page1 = generator()->CreateItemWithTempFile();
OfflinePageItem page2 = generator()->CreateItemWithTempFile();
// Set an access count of 200 to avoid falling in the same bucket.
generator()->SetAccessCount(200);
OfflinePageItem page3 = generator()->CreateItemWithTempFile();
store_test_util()->InsertItem(page1);
store_test_util()->InsertItem(page2);
store_test_util()->InsertItem(page3);
EXPECT_EQ(3LL, store_test_util()->GetPageCount());
EXPECT_TRUE(base::PathExists(page1.file_path));
EXPECT_TRUE(base::PathExists(page2.file_path));
EXPECT_TRUE(base::PathExists(page3.file_path));
// The pages with the offline ids will be removed from the store.
std::vector<int64_t> offline_ids({page1.offline_id, page3.offline_id});
auto task = DeletePageTask::CreateTaskMatchingOfflineIds(
store(), delete_page_callback(), offline_ids);
RunTask(std::move(task));
EXPECT_EQ(DeletePageResult::SUCCESS, last_delete_page_result());
EXPECT_EQ(2UL, last_deleted_page_infos().size());
EXPECT_EQ(1LL, store_test_util()->GetPageCount());
EXPECT_TRUE(CheckPageDeleted(page1));
EXPECT_FALSE(CheckPageDeleted(page2));
EXPECT_TRUE(CheckPageDeleted(page3));
histogram_tester()->ExpectTotalCount(
model_utils::AddHistogramSuffix(page1.client_id.name_space,
"OfflinePages.PageLifetime"),
2);
histogram_tester()->ExpectTotalCount(
model_utils::AddHistogramSuffix(page1.client_id.name_space,
"OfflinePages.AccessCount"),
2);
histogram_tester()->ExpectBucketCount(
model_utils::AddHistogramSuffix(page1.client_id.name_space,
"OfflinePages.AccessCount"),
0, 1);
histogram_tester()->ExpectBucketCount(
model_utils::AddHistogramSuffix(page1.client_id.name_space,
"OfflinePages.AccessCount"),
200, 1);
}
TEST_F(DeletePageTaskTest, DeletePageByOfflineIdNotFound) {
generator()->SetNamespace(kTestNamespace);
OfflinePageItem page1 = generator()->CreateItemWithTempFile();
OfflinePageItem page2 = generator()->CreateItemWithTempFile();
OfflinePageItem page3 = generator()->CreateItemWithTempFile();
store_test_util()->InsertItem(page1);
store_test_util()->InsertItem(page2);
store_test_util()->InsertItem(page3);
EXPECT_EQ(3LL, store_test_util()->GetPageCount());
// The pages with the offline ids will be removed from the store. But since
// the id isn't in the store, there will be no pages deleted and the result
// will be success since there's no NOT_FOUND anymore.
// This *might* break if any of the generated offline ids above equals to the
// constant value defined above.
std::vector<int64_t> offline_ids({kTestOfflineIdNoMatch});
auto task = DeletePageTask::CreateTaskMatchingOfflineIds(
store(), delete_page_callback(), offline_ids);
RunTask(std::move(task));
EXPECT_EQ(DeletePageResult::SUCCESS, last_delete_page_result());
EXPECT_EQ(0UL, last_deleted_page_infos().size());
EXPECT_EQ(3LL, store_test_util()->GetPageCount());
EXPECT_FALSE(CheckPageDeleted(page1));
EXPECT_FALSE(CheckPageDeleted(page2));
EXPECT_FALSE(CheckPageDeleted(page3));
histogram_tester()->ExpectTotalCount(
model_utils::AddHistogramSuffix(page1.client_id.name_space,
"OfflinePages.PageLifetime"),
0);
histogram_tester()->ExpectTotalCount(
model_utils::AddHistogramSuffix(page1.client_id.name_space,
"OfflinePages.AccessCount"),
0);
}
TEST_F(DeletePageTaskTest, DeletePageByClientId) {
// Add 3 pages and try to delete 2 of them using client id.
generator()->SetNamespace(kTestNamespace);
OfflinePageItem page1 = generator()->CreateItemWithTempFile();
OfflinePageItem page2 = generator()->CreateItemWithTempFile();
generator()->SetAccessCount(200);
OfflinePageItem page3 = generator()->CreateItemWithTempFile();
store_test_util()->InsertItem(page1);
store_test_util()->InsertItem(page2);
store_test_util()->InsertItem(page3);
EXPECT_EQ(3LL, store_test_util()->GetPageCount());
EXPECT_TRUE(base::PathExists(page1.file_path));
EXPECT_TRUE(base::PathExists(page2.file_path));
EXPECT_TRUE(base::PathExists(page3.file_path));
std::vector<ClientId> client_ids({page1.client_id, page3.client_id});
auto task = DeletePageTask::CreateTaskMatchingClientIds(
store(), delete_page_callback(), client_ids);
RunTask(std::move(task));
EXPECT_EQ(DeletePageResult::SUCCESS, last_delete_page_result());
EXPECT_EQ(2UL, last_deleted_page_infos().size());
EXPECT_EQ(1LL, store_test_util()->GetPageCount());
EXPECT_TRUE(CheckPageDeleted(page1));
EXPECT_FALSE(CheckPageDeleted(page2));
EXPECT_TRUE(CheckPageDeleted(page3));
histogram_tester()->ExpectTotalCount(
model_utils::AddHistogramSuffix(page1.client_id.name_space,
"OfflinePages.PageLifetime"),
2);
histogram_tester()->ExpectTotalCount(
model_utils::AddHistogramSuffix(page1.client_id.name_space,
"OfflinePages.AccessCount"),
2);
histogram_tester()->ExpectBucketCount(
model_utils::AddHistogramSuffix(page1.client_id.name_space,
"OfflinePages.AccessCount"),
0, 1);
histogram_tester()->ExpectBucketCount(
model_utils::AddHistogramSuffix(page1.client_id.name_space,
"OfflinePages.AccessCount"),
200, 1);
}
TEST_F(DeletePageTaskTest, DeletePageByClientIdNotFound) {
generator()->SetNamespace(kTestNamespace);
OfflinePageItem page1 = generator()->CreateItemWithTempFile();
OfflinePageItem page2 = generator()->CreateItemWithTempFile();
OfflinePageItem page3 = generator()->CreateItemWithTempFile();
store_test_util()->InsertItem(page1);
store_test_util()->InsertItem(page2);
store_test_util()->InsertItem(page3);
EXPECT_EQ(3LL, store_test_util()->GetPageCount());
// The pages with the client ids will be removed from the store. But since
// the id isn't in the store, there will be no pages deleted and the result
// will be success since there's no NOT_FOUND anymore.
std::vector<ClientId> client_ids({kTestClientIdNoMatch});
auto task = DeletePageTask::CreateTaskMatchingClientIds(
store(), delete_page_callback(), client_ids);
RunTask(std::move(task));
EXPECT_EQ(DeletePageResult::SUCCESS, last_delete_page_result());
EXPECT_EQ(0UL, last_deleted_page_infos().size());
EXPECT_EQ(3LL, store_test_util()->GetPageCount());
histogram_tester()->ExpectTotalCount(
model_utils::AddHistogramSuffix(page1.client_id.name_space,
"OfflinePages.PageLifetime"),
0);
histogram_tester()->ExpectTotalCount(
model_utils::AddHistogramSuffix(page1.client_id.name_space,
"OfflinePages.AccessCount"),
0);
}
TEST_F(DeletePageTaskTest, DeletePageByClientIdAndOrigin) {
// Add 3 pages and try to delete 2 of them using client id and origin
// Page1: {test namespace, random id, abc.xyz}
// Page2: {test namespace, foo, abc.xyz}
// Page3: {test namespace, foo, <none>}
generator()->SetNamespace(kTestNamespace);
generator()->SetRequestOrigin("abc.xyz");
OfflinePageItem page1 = generator()->CreateItemWithTempFile();
generator()->SetId("foo");
OfflinePageItem page2 = generator()->CreateItemWithTempFile();
generator()->SetRequestOrigin("");
OfflinePageItem page3 = generator()->CreateItemWithTempFile();
store_test_util()->InsertItem(page1);
store_test_util()->InsertItem(page2);
store_test_util()->InsertItem(page3);
std::vector<ClientId> client_ids({page1.client_id, page2.client_id});
auto task = DeletePageTask::CreateTaskMatchingClientIdsAndOrigin(
store(), delete_page_callback(), client_ids, "abc.xyz");
RunTask(std::move(task));
EXPECT_EQ(DeletePageResult::SUCCESS, last_delete_page_result());
EXPECT_EQ(2UL, last_deleted_page_infos().size());
EXPECT_EQ(1LL, store_test_util()->GetPageCount());
EXPECT_TRUE(CheckPageDeleted(page1));
EXPECT_TRUE(CheckPageDeleted(page2));
EXPECT_FALSE(CheckPageDeleted(page3));
histogram_tester()->ExpectTotalCount(
model_utils::AddHistogramSuffix(page1.client_id.name_space,
"OfflinePages.PageLifetime"),
2);
histogram_tester()->ExpectTotalCount(
model_utils::AddHistogramSuffix(page1.client_id.name_space,
"OfflinePages.AccessCount"),
2);
}
TEST_F(DeletePageTaskTest, DeletePageByClientIdAndOriginNotFound) {
generator()->SetNamespace(kTestNamespace);
OfflinePageItem page1 = generator()->CreateItemWithTempFile();
OfflinePageItem page2 = generator()->CreateItemWithTempFile();
OfflinePageItem page3 = generator()->CreateItemWithTempFile();
store_test_util()->InsertItem(page1);
store_test_util()->InsertItem(page2);
store_test_util()->InsertItem(page3);
EXPECT_EQ(3LL, store_test_util()->GetPageCount());
// The pages with the client ids will be removed from the store given that
// their origin matches. But since the origin isn't in the store, there will
// be no pages deleted and the result will be success since there's no
// NOT_FOUND anymore.
std::vector<ClientId> client_ids(
{page1.client_id, page2.client_id, page3.client_id});
auto task = DeletePageTask::CreateTaskMatchingClientIdsAndOrigin(
store(), delete_page_callback(), client_ids, "abc.xyz");
RunTask(std::move(task));
EXPECT_EQ(DeletePageResult::SUCCESS, last_delete_page_result());
EXPECT_EQ(0UL, last_deleted_page_infos().size());
EXPECT_EQ(3LL, store_test_util()->GetPageCount());
histogram_tester()->ExpectTotalCount(
model_utils::AddHistogramSuffix(page1.client_id.name_space,
"OfflinePages.PageLifetime"),
0);
histogram_tester()->ExpectTotalCount(
model_utils::AddHistogramSuffix(page1.client_id.name_space,
"OfflinePages.AccessCount"),
0);
}
TEST_F(DeletePageTaskTest, DeletePageByUrlPredicate) {
// Add 3 pages and try to delete 2 of them using url predicate.
generator()->SetNamespace(kTestNamespace);
generator()->SetUrl(kTestUrl1);
OfflinePageItem page1 = generator()->CreateItemWithTempFile();
generator()->SetAccessCount(200);
OfflinePageItem page2 = generator()->CreateItemWithTempFile();
generator()->SetUrl(kTestUrl2);
OfflinePageItem page3 = generator()->CreateItemWithTempFile();
store_test_util()->InsertItem(page1);
store_test_util()->InsertItem(page2);
store_test_util()->InsertItem(page3);
EXPECT_EQ(3LL, store_test_util()->GetPageCount());
EXPECT_TRUE(base::PathExists(page1.file_path));
EXPECT_TRUE(base::PathExists(page2.file_path));
EXPECT_TRUE(base::PathExists(page3.file_path));
// Delete all pages with url contains example.com, which are with kTestUrl1.
UrlPredicate predicate = base::BindRepeating([](const GURL& url) -> bool {
return url.spec().find("example.com") != std::string::npos;
});
auto task = DeletePageTask::CreateTaskMatchingUrlPredicateForCachedPages(
store(), delete_page_callback(), policy_controller(), predicate);
RunTask(std::move(task));
EXPECT_EQ(DeletePageResult::SUCCESS, last_delete_page_result());
EXPECT_EQ(2UL, last_deleted_page_infos().size());
EXPECT_EQ(predicate.Run(page1.url), CheckPageDeleted(page1));
EXPECT_EQ(predicate.Run(page2.url), CheckPageDeleted(page2));
EXPECT_EQ(predicate.Run(page3.url), CheckPageDeleted(page3));
histogram_tester()->ExpectTotalCount(
model_utils::AddHistogramSuffix(page1.client_id.name_space,
"OfflinePages.PageLifetime"),
2);
histogram_tester()->ExpectTotalCount(
model_utils::AddHistogramSuffix(page1.client_id.name_space,
"OfflinePages.AccessCount"),
2);
histogram_tester()->ExpectBucketCount(
model_utils::AddHistogramSuffix(page1.client_id.name_space,
"OfflinePages.AccessCount"),
0, 1);
histogram_tester()->ExpectBucketCount(
model_utils::AddHistogramSuffix(page1.client_id.name_space,
"OfflinePages.AccessCount"),
200, 1);
}
TEST_F(DeletePageTaskTest, DeletePageByUrlPredicateNotFound) {
// Add 3 pages and try to delete 2 of them using url predicate.
generator()->SetNamespace(kTestNamespace);
generator()->SetUrl(kTestUrl1);
OfflinePageItem page1 = generator()->CreateItemWithTempFile();
OfflinePageItem page2 = generator()->CreateItemWithTempFile();
generator()->SetUrl(kTestUrl2);
OfflinePageItem page3 = generator()->CreateItemWithTempFile();
store_test_util()->InsertItem(page1);
store_test_util()->InsertItem(page2);
store_test_util()->InsertItem(page3);
EXPECT_EQ(3LL, store_test_util()->GetPageCount());
EXPECT_TRUE(base::PathExists(page1.file_path));
EXPECT_TRUE(base::PathExists(page2.file_path));
EXPECT_TRUE(base::PathExists(page3.file_path));
// Return false for all pages so that no pages will be deleted.
UrlPredicate predicate =
base::BindRepeating([](const GURL& url) -> bool { return false; });
auto task = DeletePageTask::CreateTaskMatchingUrlPredicateForCachedPages(
store(), delete_page_callback(), policy_controller(), predicate);
RunTask(std::move(task));
EXPECT_EQ(DeletePageResult::SUCCESS, last_delete_page_result());
EXPECT_EQ(0UL, last_deleted_page_infos().size());
EXPECT_FALSE(CheckPageDeleted(page1));
EXPECT_FALSE(CheckPageDeleted(page2));
EXPECT_FALSE(CheckPageDeleted(page3));
histogram_tester()->ExpectTotalCount(
model_utils::AddHistogramSuffix(page1.client_id.name_space,
"OfflinePages.PageLifetime"),
0);
histogram_tester()->ExpectTotalCount(
model_utils::AddHistogramSuffix(page1.client_id.name_space,
"OfflinePages.AccessCount"),
0);
}
TEST_F(DeletePageTaskTest, DeletePageForPageLimit) {
// Add 3 pages, the kTestNamespace has a limit of 1 for page per url.
generator()->SetNamespace(kTestNamespace);
generator()->SetUrl(kTestUrl1);
// Guarantees that page1 will be deleted by making it older.
base::Time now = OfflineTimeNow();
generator()->SetLastAccessTime(now - base::TimeDelta::FromMinutes(5));
OfflinePageItem page1 = generator()->CreateItemWithTempFile();
generator()->SetLastAccessTime(now);
OfflinePageItem page2 = generator()->CreateItemWithTempFile();
OfflinePageItem page = generator()->CreateItem();
generator()->SetUrl(kTestUrl2);
OfflinePageItem page3 = generator()->CreateItemWithTempFile();
store_test_util()->InsertItem(page1);
store_test_util()->InsertItem(page2);
store_test_util()->InsertItem(page3);
EXPECT_EQ(3LL, store_test_util()->GetPageCount());
EXPECT_TRUE(base::PathExists(page1.file_path));
EXPECT_TRUE(base::PathExists(page2.file_path));
EXPECT_TRUE(base::PathExists(page3.file_path));
auto task = DeletePageTask::CreateTaskDeletingForPageLimit(
store(), delete_page_callback(), policy_controller(), page);
RunTask(std::move(task));
EXPECT_EQ(DeletePageResult::SUCCESS, last_delete_page_result());
EXPECT_EQ(1UL, last_deleted_page_infos().size());
EXPECT_TRUE(CheckPageDeleted(page1));
EXPECT_FALSE(CheckPageDeleted(page2));
EXPECT_FALSE(CheckPageDeleted(page3));
histogram_tester()->ExpectTotalCount(
model_utils::AddHistogramSuffix(page1.client_id.name_space,
"OfflinePages.PageLifetime"),
1);
histogram_tester()->ExpectUniqueSample(
model_utils::AddHistogramSuffix(page1.client_id.name_space,
"OfflinePages.AccessCount"),
0, 1);
}
TEST_F(DeletePageTaskTest, DeletePageForPageLimit_UnlimitedNamespace) {
// Add 3 pages, the kTestNamespace has a limit of 1 for page per url.
generator()->SetNamespace(kDownloadNamespace);
generator()->SetUrl(kTestUrl1);
OfflinePageItem page1 = generator()->CreateItemWithTempFile();
OfflinePageItem page2 = generator()->CreateItemWithTempFile();
OfflinePageItem page = generator()->CreateItem();
generator()->SetUrl(kTestUrl2);
OfflinePageItem page3 = generator()->CreateItemWithTempFile();
store_test_util()->InsertItem(page1);
store_test_util()->InsertItem(page2);
store_test_util()->InsertItem(page3);
EXPECT_EQ(3LL, store_test_util()->GetPageCount());
EXPECT_TRUE(base::PathExists(page1.file_path));
EXPECT_TRUE(base::PathExists(page2.file_path));
EXPECT_TRUE(base::PathExists(page3.file_path));
auto task = DeletePageTask::CreateTaskDeletingForPageLimit(
store(), delete_page_callback(), policy_controller(), page);
RunTask(std::move(task));
// Since there's no limit for page per url of Download Namespace, the result
// should be success with no page deleted.
EXPECT_EQ(DeletePageResult::SUCCESS, last_delete_page_result());
EXPECT_EQ(0UL, last_deleted_page_infos().size());
histogram_tester()->ExpectTotalCount(
model_utils::AddHistogramSuffix(page1.client_id.name_space,
"OfflinePages.PageLifetime"),
0);
histogram_tester()->ExpectTotalCount(
model_utils::AddHistogramSuffix(page1.client_id.name_space,
"OfflinePages.AccessCount"),
0);
}
} // namespace offline_pages