blob: 094b009f2572ef04aa548a1e06c279240d2c9fb2 [file] [log] [blame]
// Copyright 2015 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 <stddef.h>
#include "base/path_service.h"
#include "base/run_loop.h"
#include "base/stl_util.h"
#include "base/strings/utf_string_conversions.h"
#include "base/threading/thread_restrictions.h"
#include "chrome/browser/task_manager/mock_web_contents_task_manager.h"
#include "chrome/browser/task_manager/providers/web_contents/web_contents_tags_manager.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/tabs/tab_strip_model.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/grit/generated_resources.h"
#include "chrome/test/base/in_process_browser_test.h"
#include "chrome/test/base/ui_test_utils.h"
#include "components/favicon/content/content_favicon_driver.h"
#include "components/favicon/core/favicon_driver.h"
#include "components/favicon/core/favicon_driver_observer.h"
#include "content/public/browser/favicon_status.h"
#include "content/public/browser/navigation_entry.h"
#include "net/test/embedded_test_server/embedded_test_server.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/page_transition_types.h"
#include "ui/base/resource/resource_bundle.h"
#include "ui/gfx/codec/png_codec.h"
#include "ui/gfx/image/image.h"
#include "ui/gfx/image/image_unittest_util.h"
#include "ui/resources/grit/ui_resources.h"
namespace task_manager {
namespace {
// Defines a test page file path along with its expected task manager reported
// values.
struct TestPageData {
const char* page_file;
const char* title;
Task::Type task_type;
int expected_prefix_message;
};
// The below test files are available in src/chrome/test/data/
// TODO(afakhry): Add more test pages here as needed (e.g. pages that are hosted
// in the tabs as apps or extensions).
const TestPageData kTestPages[] = {
{
"/title1.html",
"",
Task::RENDERER,
IDS_TASK_MANAGER_TAB_PREFIX
},
{
"/title2.html",
"Title Of Awesomeness",
Task::RENDERER,
IDS_TASK_MANAGER_TAB_PREFIX
},
{
"/title3.html",
"Title Of More Awesomeness",
Task::RENDERER,
IDS_TASK_MANAGER_TAB_PREFIX
},
};
const size_t kTestPagesLength = base::size(kTestPages);
// Blocks till the current page uses a specific icon URL.
class FaviconWaiter : public favicon::FaviconDriverObserver {
public:
explicit FaviconWaiter(favicon::ContentFaviconDriver* driver)
: driver_(driver) {
driver_->AddObserver(this);
}
void WaitForFaviconWithURL(const GURL& url) {
if (GetCurrentFaviconURL() == url) {
driver_->RemoveObserver(this);
return;
}
target_favicon_url_ = url;
base::RunLoop run_loop;
quit_closure_ = run_loop.QuitClosure();
run_loop.Run();
}
private:
GURL GetCurrentFaviconURL() {
const content::NavigationController& controller =
driver_->web_contents()->GetController();
content::NavigationEntry* entry = controller.GetLastCommittedEntry();
return entry ? entry->GetFavicon().url : GURL();
}
void OnFaviconUpdated(favicon::FaviconDriver* favicon_driver,
NotificationIconType notification_icon_type,
const GURL& icon_url,
bool icon_url_changed,
const gfx::Image& image) override {
if (notification_icon_type == NON_TOUCH_16_DIP &&
icon_url == target_favicon_url_) {
driver_->RemoveObserver(this);
if (!quit_closure_.is_null())
quit_closure_.Run();
}
}
favicon::ContentFaviconDriver* driver_;
GURL target_favicon_url_;
base::Closure quit_closure_;
DISALLOW_COPY_AND_ASSIGN(FaviconWaiter);
};
} // namespace
// Defines a browser test class for testing the task manager tracking of tab
// contents.
class TabContentsTagTest : public InProcessBrowserTest {
public:
TabContentsTagTest() { EXPECT_TRUE(embedded_test_server()->Start()); }
~TabContentsTagTest() override {}
void AddNewTestTabAt(int index, const char* test_page_file) {
int tabs_count_before = tabs_count();
GURL url = GetUrlOfFile(test_page_file);
AddTabAtIndex(index, url, ui::PAGE_TRANSITION_TYPED);
EXPECT_EQ(++tabs_count_before, tabs_count());
}
void NavigateToUrl(const char* test_page_file) {
ui_test_utils::NavigateToURL(browser(), GetUrlOfFile(test_page_file));
}
void CloseTabAt(int index) {
browser()->tab_strip_model()->CloseWebContentsAt(index,
TabStripModel::CLOSE_NONE);
}
base::string16 GetTestPageExpectedTitle(const TestPageData& page_data) const {
// Pages with no title should fall back to their URL.
base::string16 title = base::UTF8ToUTF16(page_data.title);
if (title.empty()) {
GURL url = GetUrlOfFile(page_data.page_file);
return GetDefaultTitleForUrl(url);
}
return l10n_util::GetStringFUTF16(page_data.expected_prefix_message, title);
}
// Returns the expected title for |url| if |url| does not specify a custom
// title (e.g. via the <title> tag).
base::string16 GetDefaultTitleForUrl(const GURL& url) const {
base::string16 title =
base::UTF8ToUTF16(url.host() + ":" + url.port() + url.path());
return l10n_util::GetStringFUTF16(IDS_TASK_MANAGER_TAB_PREFIX, title);
}
base::string16 GetAboutBlankExpectedTitle() const {
return l10n_util::GetStringFUTF16(IDS_TASK_MANAGER_TAB_PREFIX,
base::UTF8ToUTF16("about:blank"));
}
int tabs_count() const { return browser()->tab_strip_model()->count(); }
const std::vector<WebContentsTag*>& tracked_tags() const {
return WebContentsTagsManager::GetInstance()->tracked_tags();
}
GURL GetUrlOfFile(const char* test_page_file) const {
return embedded_test_server()->GetURL(test_page_file);
}
private:
DISALLOW_COPY_AND_ASSIGN(TabContentsTagTest);
};
// Tests that TabContentsTags are being recorded correctly by the
// WebContentsTagsManager.
IN_PROC_BROWSER_TEST_F(TabContentsTagTest, BasicTagsTracking) {
// Browser tests start with a single tab.
EXPECT_EQ(1, tabs_count());
EXPECT_EQ(1U, tracked_tags().size());
// Add a bunch of tabs and make sure we're tracking them.
AddNewTestTabAt(0, kTestPages[0].page_file);
EXPECT_EQ(2, tabs_count());
EXPECT_EQ(2U, tracked_tags().size());
AddNewTestTabAt(1, kTestPages[1].page_file);
EXPECT_EQ(3, tabs_count());
EXPECT_EQ(3U, tracked_tags().size());
// Navigating the selected tab doesn't change the number of tabs nor the
// number of tags.
NavigateToUrl(kTestPages[2].page_file);
EXPECT_EQ(3, tabs_count());
EXPECT_EQ(3U, tracked_tags().size());
// Close a bunch of tabs and make sure we can notice that.
CloseTabAt(0);
CloseTabAt(0);
EXPECT_EQ(1, tabs_count());
EXPECT_EQ(1U, tracked_tags().size());
}
// Tests that the pre-task-manager-existing tabs are given to the task manager
// once it starts observing.
IN_PROC_BROWSER_TEST_F(TabContentsTagTest, PreExistingTaskProviding) {
// We start with the "about:blank" tab.
EXPECT_EQ(1, tabs_count());
EXPECT_EQ(1U, tracked_tags().size());
// Add a bunch of tabs and make sure when the task manager is created and
// starts observing sees those pre-existing tabs.
AddNewTestTabAt(0, kTestPages[0].page_file);
EXPECT_EQ(2, tabs_count());
EXPECT_EQ(2U, tracked_tags().size());
AddNewTestTabAt(1, kTestPages[1].page_file);
EXPECT_EQ(3, tabs_count());
EXPECT_EQ(3U, tracked_tags().size());
MockWebContentsTaskManager task_manager;
EXPECT_TRUE(task_manager.tasks().empty());
task_manager.StartObserving();
EXPECT_EQ(3U, task_manager.tasks().size());
}
// Tests that the task manager sees the correct tabs with their correct
// corresponding tasks data.
IN_PROC_BROWSER_TEST_F(TabContentsTagTest, PostExistingTaskProviding) {
// We start with the "about:blank" tab.
EXPECT_EQ(1, tabs_count());
EXPECT_EQ(1U, tracked_tags().size());
MockWebContentsTaskManager task_manager;
EXPECT_TRUE(task_manager.tasks().empty());
task_manager.StartObserving();
ASSERT_EQ(1U, task_manager.tasks().size());
const Task* first_tab_task = task_manager.tasks().front();
EXPECT_EQ(Task::RENDERER, first_tab_task->GetType());
EXPECT_EQ(GetAboutBlankExpectedTitle(), first_tab_task->title());
// Add the test pages in order and test the provided tasks.
for (const auto& test_page_data : kTestPages) {
AddNewTestTabAt(0, test_page_data.page_file);
const Task* task = task_manager.tasks().back();
EXPECT_EQ(test_page_data.task_type, task->GetType());
EXPECT_EQ(GetTestPageExpectedTitle(test_page_data), task->title());
}
EXPECT_EQ(1 + kTestPagesLength, task_manager.tasks().size());
// Close the last tab that was added. Make sure it doesn't show up in the
// task manager.
CloseTabAt(0);
EXPECT_EQ(kTestPagesLength, task_manager.tasks().size());
const base::string16 closed_tab_title =
GetTestPageExpectedTitle(kTestPages[kTestPagesLength - 1]);
for (const auto* task : task_manager.tasks())
EXPECT_NE(closed_tab_title, task->title());
}
// Test that the default favicon is shown in the task manager after navigating
// from a page with a favicon to a page without a favicon. crbug.com/528924
IN_PROC_BROWSER_TEST_F(TabContentsTagTest, NavigateToPageNoFavicon) {
// We start with the "about:blank" tab.
MockWebContentsTaskManager task_manager;
task_manager.StartObserving();
ASSERT_EQ(1, tabs_count());
ASSERT_EQ(1U, tracked_tags().size());
// Navigate to a page with a favicon.
GURL favicon_page_url = GetUrlOfFile("/favicon/page_with_favicon.html");
ui_test_utils::NavigateToURL(browser(), favicon_page_url);
ASSERT_GE(1U, task_manager.tasks().size());
Task* task = task_manager.tasks().back();
ASSERT_EQ(GetDefaultTitleForUrl(favicon_page_url), task->title());
// Wait for the browser to download the favicon.
favicon::ContentFaviconDriver* favicon_driver =
favicon::ContentFaviconDriver::FromWebContents(
browser()->tab_strip_model()->GetActiveWebContents());
FaviconWaiter waiter(favicon_driver);
waiter.WaitForFaviconWithURL(GetUrlOfFile("/favicon/icon.png"));
// Check that the task manager uses the specified favicon for the page.
base::FilePath test_dir;
base::PathService::Get(chrome::DIR_TEST_DATA, &test_dir);
std::string favicon_string;
{
base::ScopedAllowBlockingForTesting allow_blocking;
base::ReadFileToString(
test_dir.AppendASCII("favicon").AppendASCII("icon.png"),
&favicon_string);
}
SkBitmap favicon_bitmap;
gfx::PNGCodec::Decode(
reinterpret_cast<const unsigned char*>(favicon_string.data()),
favicon_string.length(), &favicon_bitmap);
ASSERT_TRUE(
gfx::test::AreBitmapsEqual(favicon_bitmap, *task->icon().bitmap()));
// Navigate to a page without a favicon.
GURL no_favicon_page_url = GetUrlOfFile("/title1.html");
ui_test_utils::NavigateToURL(browser(), no_favicon_page_url);
ASSERT_EQ(GetDefaultTitleForUrl(no_favicon_page_url), task->title());
// Check that the task manager uses the default favicon for the page.
gfx::Image default_favicon_image =
ui::ResourceBundle::GetSharedInstance().GetNativeImageNamed(
IDR_DEFAULT_FAVICON);
EXPECT_TRUE(gfx::test::AreImagesEqual(default_favicon_image,
gfx::Image(task->icon())));
}
} // namespace task_manager