blob: a11c7d7531d112eb20d2449334a08034398175e6 [file] [log] [blame]
// Copyright 2018 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 "base/files/file_path.h"
#include "base/test/scoped_feature_list.h"
#include "build/build_config.h"
#include "chrome/browser/browsing_data/navigation_entry_remover.h"
#include "chrome/browser/sessions/tab_restore_service_factory.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_commands.h"
#include "chrome/browser/ui/browser_list.h"
#include "chrome/browser/ui/tabs/tab_strip_model.h"
#include "chrome/test/base/in_process_browser_test.h"
#include "chrome/test/base/ui_test_utils.h"
#include "components/browsing_data/core/features.h"
#include "components/sessions/core/tab_restore_service.h"
#include "content/public/browser/navigation_controller.h"
#include "content/public/browser/navigation_entry.h"
#include "content/public/browser/notification_service.h"
#include "content/public/browser/notification_types.h"
#include "content/public/browser/web_contents.h"
#include "content/public/test/test_navigation_observer.h"
#include "url/gurl.h"
using history::DeletionInfo;
class NavigationEntryRemoverTest : public InProcessBrowserTest {
protected:
void SetUpOnMainThread() override {
feature_list_.InitWithFeatures(
{browsing_data::features::kRemoveNavigationHistory}, {});
auto path = base::FilePath(FILE_PATH_LITERAL("browsing_data"));
url_a_ = ui_test_utils::GetTestUrl(
path, base::FilePath(FILE_PATH_LITERAL("a.html")));
url_b_ = ui_test_utils::GetTestUrl(
path, base::FilePath(FILE_PATH_LITERAL("b.html")));
url_c_ = ui_test_utils::GetTestUrl(
path, base::FilePath(FILE_PATH_LITERAL("c.html")));
url_d_ = ui_test_utils::GetTestUrl(
path, base::FilePath(FILE_PATH_LITERAL("d.html")));
about_blank_ = GURL("about:blank");
}
void AddNavigations(Browser* browser, const std::vector<GURL>& urls) {
for (const GURL& url : urls) {
ui_test_utils::NavigateToURLWithDisposition(
browser, url, WindowOpenDisposition::CURRENT_TAB,
ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
}
}
void AddTab(Browser* browser, const std::vector<GURL>& urls) {
ui_test_utils::NavigateToURLWithDisposition(
browser, urls[0], WindowOpenDisposition::NEW_FOREGROUND_TAB,
ui_test_utils::BROWSER_TEST_WAIT_FOR_TAB |
ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
AddNavigations(browser, {urls.begin() + 1, urls.end()});
}
void AddBrowser(Browser* browser, const std::vector<GURL>& urls) {
ui_test_utils::NavigateToURLWithDisposition(
browser, urls[0], WindowOpenDisposition::NEW_WINDOW,
ui_test_utils::BROWSER_TEST_WAIT_FOR_BROWSER);
AddNavigations(BrowserList::GetInstance()->GetLastActive(),
{urls.begin() + 1, urls.end()});
}
void GoBack(content::WebContents* web_contents) {
content::WindowedNotificationObserver load_stop_observer(
content::NOTIFICATION_LOAD_STOP,
content::NotificationService::AllSources());
web_contents->GetController().GoBack();
load_stop_observer.Wait();
}
std::vector<GURL> GetEntries() {
std::vector<GURL> urls;
for (Browser* browser : *BrowserList::GetInstance()) {
for (int j = 0; j < browser->tab_strip_model()->count(); j++) {
content::NavigationController* controller =
&browser->tab_strip_model()->GetWebContentsAt(j)->GetController();
for (int i = 0; i < controller->GetEntryCount(); i++)
urls.push_back(controller->GetEntryAtIndex(i)->GetURL());
}
}
return urls;
}
DeletionInfo CreateDeletionInfo(base::Time from,
base::Time to,
std::set<GURL> restrict_urls = {}) {
return DeletionInfo(history::DeletionTimeRange(from, to), false, {}, {},
restrict_urls.empty() ? base::Optional<std::set<GURL>>()
: restrict_urls);
}
// Helper to compare vectors. The macro gets confused by EXPECT_EQ(v, {a,b}).
void ExpectEntries(const std::vector<GURL>& expected,
const std::vector<GURL>& actual) {
EXPECT_EQ(expected, actual);
}
GURL url_a_;
GURL url_b_;
GURL url_c_;
GURL url_d_;
GURL about_blank_;
private:
base::test::ScopedFeatureList feature_list_;
};
// === Tests for helper functions ===
IN_PROC_BROWSER_TEST_F(NavigationEntryRemoverTest, AddNavigation) {
// A new browser starts with about:blank. Add a,b,c and check.
ExpectEntries({about_blank_}, GetEntries());
AddNavigations(browser(), {url_a_, url_b_, url_c_});
ExpectEntries({about_blank_, url_a_, url_b_, url_c_}, GetEntries());
}
IN_PROC_BROWSER_TEST_F(NavigationEntryRemoverTest, AddTab) {
EXPECT_EQ(1, browser()->tab_strip_model()->count());
AddTab(browser(), {url_a_});
EXPECT_EQ(2, browser()->tab_strip_model()->count());
ExpectEntries({about_blank_, url_a_}, GetEntries());
AddTab(browser(), {url_b_, url_c_});
EXPECT_EQ(3, browser()->tab_strip_model()->count());
ExpectEntries({about_blank_, url_a_, url_b_, url_c_}, GetEntries());
}
IN_PROC_BROWSER_TEST_F(NavigationEntryRemoverTest, AddWindow) {
EXPECT_EQ(1U, BrowserList::GetInstance()->size());
AddBrowser(browser(), {url_a_, url_b_});
EXPECT_EQ(2U, BrowserList::GetInstance()->size());
ExpectEntries({about_blank_, url_a_, url_b_}, GetEntries());
AddBrowser(browser(), {url_c_, url_d_});
EXPECT_EQ(3U, BrowserList::GetInstance()->size());
ExpectEntries({about_blank_, url_a_, url_b_, url_c_, url_d_}, GetEntries());
}
IN_PROC_BROWSER_TEST_F(NavigationEntryRemoverTest, GoBack) {
AddNavigations(browser(), {url_a_, url_b_, url_c_});
auto* web_contents = browser()->tab_strip_model()->GetActiveWebContents();
EXPECT_EQ(url_c_, web_contents->GetLastCommittedURL());
GoBack(web_contents);
EXPECT_EQ(url_b_, web_contents->GetLastCommittedURL());
ExpectEntries({about_blank_, url_a_, url_b_, url_c_}, GetEntries());
}
// === The actual tests ===
IN_PROC_BROWSER_TEST_F(NavigationEntryRemoverTest, DeleteIndividual) {
AddNavigations(browser(), {url_a_, url_b_, url_c_, url_d_});
browsing_data::RemoveNavigationEntries(
browser()->profile(),
DeletionInfo::ForUrls({history::URLResult(url_b_, base::Time())}, {}));
ExpectEntries({about_blank_, url_a_, url_c_, url_d_}, GetEntries());
browsing_data::RemoveNavigationEntries(
browser()->profile(),
DeletionInfo::ForUrls({history::URLResult(url_c_, base::Time())}, {}));
ExpectEntries({about_blank_, url_a_, url_d_}, GetEntries());
}
IN_PROC_BROWSER_TEST_F(NavigationEntryRemoverTest, DeleteAfterNavigation) {
AddNavigations(browser(), {url_a_, url_b_});
browsing_data::RemoveNavigationEntries(
browser()->profile(),
DeletionInfo::ForUrls({history::URLResult(url_b_, base::Time())}, {}));
// The commited entry can't be removed.
ExpectEntries({about_blank_, url_a_, url_b_}, GetEntries());
AddNavigations(browser(), {url_c_});
browsing_data::RemoveNavigationEntries(
browser()->profile(),
DeletionInfo::ForUrls({history::URLResult(url_b_, base::Time())}, {}));
ExpectEntries({about_blank_, url_a_, url_c_}, GetEntries());
}
IN_PROC_BROWSER_TEST_F(NavigationEntryRemoverTest, DeleteAll) {
AddNavigations(browser(), {url_a_, url_b_, url_c_});
browsing_data::RemoveNavigationEntries(browser()->profile(),
DeletionInfo::ForAllHistory());
ExpectEntries({url_c_}, GetEntries());
}
IN_PROC_BROWSER_TEST_F(NavigationEntryRemoverTest, DeleteRestricted) {
AddNavigations(browser(), {url_a_, url_b_, url_c_});
browsing_data::RemoveNavigationEntries(
browser()->profile(),
CreateDeletionInfo(base::Time(), base::Time::Now(), {url_b_}));
ExpectEntries({about_blank_, url_a_, url_c_}, GetEntries());
}
IN_PROC_BROWSER_TEST_F(NavigationEntryRemoverTest, DeleteRange) {
base::Time t1 = base::Time::Now();
AddNavigations(browser(), {url_a_});
base::Time t2 = base::Time::Now();
AddNavigations(browser(), {url_b_});
base::Time t3 = base::Time::Now();
AddNavigations(browser(), {url_c_, url_d_});
ASSERT_NE(t1, t2);
ASSERT_NE(t2, t3);
browsing_data::RemoveNavigationEntries(browser()->profile(),
CreateDeletionInfo(t2, t3));
ExpectEntries({about_blank_, url_a_, url_c_, url_d_}, GetEntries());
browsing_data::RemoveNavigationEntries(browser()->profile(),
CreateDeletionInfo(base::Time(), t1));
ExpectEntries({url_a_, url_c_, url_d_}, GetEntries());
browsing_data::RemoveNavigationEntries(browser()->profile(),
CreateDeletionInfo(t3, base::Time()));
ExpectEntries({url_a_, url_d_}, GetEntries());
}
IN_PROC_BROWSER_TEST_F(NavigationEntryRemoverTest, DeleteRangeRestricted) {
base::Time t1 = base::Time::Now();
AddNavigations(browser(), {url_a_});
base::Time t2 = base::Time::Now();
AddNavigations(browser(), {url_b_});
base::Time t3 = base::Time::Now();
AddNavigations(browser(), {url_c_, url_a_});
ASSERT_NE(t1, t2);
ASSERT_NE(t2, t3);
browsing_data::RemoveNavigationEntries(browser()->profile(),
CreateDeletionInfo(t1, t3, {url_b_}));
ExpectEntries({about_blank_, url_a_, url_c_, url_a_}, GetEntries());
browsing_data::RemoveNavigationEntries(
browser()->profile(), CreateDeletionInfo(base::Time(), t2, {url_a_}));
ExpectEntries({about_blank_, url_c_, url_a_}, GetEntries());
}
IN_PROC_BROWSER_TEST_F(NavigationEntryRemoverTest, DeleteAllAfterNavigation) {
AddNavigations(browser(), {url_a_, url_b_, url_c_});
browsing_data::RemoveNavigationEntries(browser()->profile(),
DeletionInfo::ForAllHistory());
ExpectEntries({url_c_}, GetEntries());
AddNavigations(browser(), {url_d_});
ExpectEntries({url_c_, url_d_}, GetEntries());
browsing_data::RemoveNavigationEntries(browser()->profile(),
DeletionInfo::ForAllHistory());
ExpectEntries({url_d_}, GetEntries());
}
IN_PROC_BROWSER_TEST_F(NavigationEntryRemoverTest, TwoTabsDeletion) {
AddNavigations(browser(), {url_a_, url_b_});
AddTab(browser(), {url_c_, url_d_});
browsing_data::RemoveNavigationEntries(browser()->profile(),
DeletionInfo::ForAllHistory());
ExpectEntries({url_b_, url_d_}, GetEntries());
}
IN_PROC_BROWSER_TEST_F(NavigationEntryRemoverTest, TwoWindowsDeletion) {
AddNavigations(browser(), {url_a_, url_b_});
AddBrowser(browser(), {url_c_, url_d_});
browsing_data::RemoveNavigationEntries(browser()->profile(),
DeletionInfo::ForAllHistory());
ExpectEntries({url_b_, url_d_}, GetEntries());
}
IN_PROC_BROWSER_TEST_F(NavigationEntryRemoverTest, GoBackAndDelete) {
AddNavigations(browser(), {url_a_, url_b_, url_c_});
GoBack(browser()->tab_strip_model()->GetActiveWebContents());
browsing_data::RemoveNavigationEntries(browser()->profile(),
DeletionInfo::ForAllHistory());
ExpectEntries({url_b_}, GetEntries());
}
IN_PROC_BROWSER_TEST_F(NavigationEntryRemoverTest, RecentTabDeletion) {
AddNavigations(browser(), {url_a_, url_b_});
AddTab(browser(), {url_c_});
AddTab(browser(), {url_d_});
chrome::CloseTab(browser());
chrome::CloseTab(browser());
sessions::TabRestoreService* tab_service =
TabRestoreServiceFactory::GetForProfile(browser()->profile());
EXPECT_EQ(2U, tab_service->entries().size());
browsing_data::RemoveNavigationEntries(
browser()->profile(),
DeletionInfo::ForUrls({history::URLResult(url_c_, base::Time())}, {}));
content::RunAllTasksUntilIdle();
EXPECT_EQ(1U, tab_service->entries().size());
auto* tab = static_cast<sessions::TabRestoreService::Tab*>(
tab_service->entries().front().get());
EXPECT_EQ(url_d_, tab->navigations.front().virtual_url());
EXPECT_TRUE(tab_service->IsLoaded());
browsing_data::RemoveNavigationEntries(
browser()->profile(),
DeletionInfo::ForUrls({history::URLResult(url_d_, base::Time())}, {}));
EXPECT_EQ(0U, tab_service->entries().size());
}
IN_PROC_BROWSER_TEST_F(NavigationEntryRemoverTest, RecentTabWindowDeletion) {
// Create a new browser with three tabs and close it.
AddBrowser(browser(), {url_a_});
Browser* new_browser = BrowserList::GetInstance()->GetLastActive();
AddTab(new_browser, {url_b_, url_c_});
AddTab(new_browser, {url_d_});
chrome::CloseWindow(new_browser);
sessions::TabRestoreService* tab_service =
TabRestoreServiceFactory::GetForProfile(browser()->profile());
EXPECT_EQ(1U, tab_service->entries().size());
ASSERT_EQ(sessions::TabRestoreService::WINDOW,
tab_service->entries().front()->type);
auto* window = static_cast<sessions::TabRestoreService::Window*>(
tab_service->entries().front().get());
EXPECT_EQ(3U, window->tabs.size());
// Delete b and d. The last opened tab should be removed.
browsing_data::RemoveNavigationEntries(
browser()->profile(),
DeletionInfo::ForUrls({history::URLResult(url_b_, base::Time()),
history::URLResult(url_d_, base::Time())},
{}));
content::RunAllTasksUntilIdle();
EXPECT_EQ(1U, tab_service->entries().size());
ASSERT_EQ(sessions::TabRestoreService::WINDOW,
tab_service->entries().front()->type);
window = static_cast<sessions::TabRestoreService::Window*>(
tab_service->entries().front().get());
EXPECT_EQ(2U, window->tabs.size());
EXPECT_EQ(2U, window->tabs.size());
EXPECT_EQ(1, window->selected_tab_index);
EXPECT_EQ(0, window->tabs[0]->tabstrip_index);
EXPECT_EQ(1, window->tabs[1]->tabstrip_index);
EXPECT_EQ(url_a_, window->tabs[0]->navigations.front().virtual_url());
EXPECT_EQ(url_c_, window->tabs[1]->navigations.front().virtual_url());
// Delete a. The Window should be converted to a Tab.
browsing_data::RemoveNavigationEntries(
browser()->profile(),
DeletionInfo::ForUrls({history::URLResult(url_a_, base::Time())}, {}));
EXPECT_EQ(1U, tab_service->entries().size());
ASSERT_EQ(sessions::TabRestoreService::TAB,
tab_service->entries().front()->type);
auto* tab = static_cast<sessions::TabRestoreService::Tab*>(
tab_service->entries().front().get());
EXPECT_EQ(url_c_, tab->navigations.front().virtual_url());
EXPECT_EQ(0, tab->tabstrip_index);
}