blob: 8fee047259f787bf868676cc0f7048daae47e4d9 [file] [log] [blame]
// Copyright (c) 2016 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/macros.h"
#include "build/build_config.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/resource_coordinator/tab_lifetime_observer.h"
#include "chrome/browser/resource_coordinator/tab_manager.h"
#include "chrome/browser/resource_coordinator/tab_manager_web_contents_data.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/tabs/tab_strip_model.h"
#include "chrome/common/url_constants.h"
#include "chrome/test/base/in_process_browser_test.h"
#include "content/public/test/test_utils.h"
#include "url/gurl.h"
using content::OpenURLParams;
using content::WebContents;
#if defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_LINUX) || \
defined(OS_CHROMEOS)
namespace resource_coordinator {
class TabLifetimeObserverTest : public InProcessBrowserTest {
public:
TabLifetimeObserverTest() {}
// Helper functions.
void set_tab_strip_model(TabStripModel* tsm) { tab_strip_model_ = tsm; }
int GetIndex(WebContents* contents) {
return tab_strip_model_->GetIndexOfWebContents(contents);
}
WebContents* GetContents(int index) {
return tab_strip_model_->GetWebContentsAt(index);
}
int64_t ContentsId(WebContents* contents) {
return TabManager::IdFromWebContents(contents);
}
private:
TabStripModel* tab_strip_model_;
};
class MockTabLifetimeObserver : public TabLifetimeObserver {
public:
MockTabLifetimeObserver()
: nb_events_(0),
contents_(nullptr),
is_discarded_(false),
is_auto_discardable_(true) {}
// TabLifetimeObserver implementation:
void OnDiscardedStateChange(content::WebContents* contents,
bool is_discarded) override {
nb_events_++;
contents_ = contents;
is_discarded_ = is_discarded;
}
void OnAutoDiscardableStateChange(content::WebContents* contents,
bool is_auto_discardable) override {
nb_events_++;
contents_ = contents;
is_auto_discardable_ = is_auto_discardable;
}
int nb_events() const { return nb_events_; }
WebContents* content() const { return contents_; }
bool is_discarded() const { return is_discarded_; }
bool is_auto_discardable() const { return is_auto_discardable_; }
private:
int nb_events_;
WebContents* contents_;
bool is_discarded_;
bool is_auto_discardable_;
DISALLOW_COPY_AND_ASSIGN(MockTabLifetimeObserver);
};
IN_PROC_BROWSER_TEST_F(TabLifetimeObserverTest, OnDiscardStateChange) {
TabManager* tab_manager = g_browser_process->GetTabManager();
auto* tsm = browser()->tab_strip_model();
set_tab_strip_model(tsm);
// Open two tabs.
OpenURLParams open1(GURL(chrome::kChromeUIAboutURL), content::Referrer(),
WindowOpenDisposition::NEW_BACKGROUND_TAB,
ui::PAGE_TRANSITION_TYPED, false);
int index_1 = GetIndex(browser()->OpenURL(open1));
OpenURLParams open2(GURL(chrome::kChromeUICreditsURL), content::Referrer(),
WindowOpenDisposition::NEW_BACKGROUND_TAB,
ui::PAGE_TRANSITION_TYPED, false);
int index_2 = GetIndex(browser()->OpenURL(open2));
// Subscribe observer to TabManager's observer list.
MockTabLifetimeObserver tabmanager_observer;
tab_manager->AddObserver(&tabmanager_observer);
// Discards both tabs and make sure the events were observed properly.
EXPECT_TRUE(tab_manager->DiscardTabById(ContentsId(GetContents(index_1)),
DiscardCondition::kProactive));
EXPECT_EQ(1, tabmanager_observer.nb_events());
EXPECT_EQ(ContentsId(GetContents(index_1)),
ContentsId(tabmanager_observer.content()));
EXPECT_TRUE(tabmanager_observer.is_discarded());
EXPECT_TRUE(tab_manager->DiscardTabById(ContentsId(GetContents(index_2)),
DiscardCondition::kProactive));
EXPECT_EQ(2, tabmanager_observer.nb_events());
EXPECT_EQ(ContentsId(GetContents(index_2)),
ContentsId(tabmanager_observer.content()));
EXPECT_TRUE(tabmanager_observer.is_discarded());
// Discarding an already discarded tab shouldn't fire the observers.
EXPECT_FALSE(tab_manager->DiscardTabById(ContentsId(GetContents(index_1)),
DiscardCondition::kProactive));
EXPECT_EQ(2, tabmanager_observer.nb_events());
// Reload tab 1.
tsm->ActivateTabAt(index_1, false);
EXPECT_EQ(index_1, tsm->active_index());
EXPECT_EQ(3, tabmanager_observer.nb_events());
EXPECT_EQ(ContentsId(GetContents(index_1)),
ContentsId(tabmanager_observer.content()));
EXPECT_FALSE(tabmanager_observer.is_discarded());
// Reloading a tab that's not discarded shouldn't fire the observers.
tsm->ActivateTabAt(index_1, false);
EXPECT_EQ(3, tabmanager_observer.nb_events());
// Reload tab 2.
tsm->ActivateTabAt(index_2, false);
EXPECT_EQ(index_2, tsm->active_index());
EXPECT_EQ(4, tabmanager_observer.nb_events());
EXPECT_EQ(ContentsId(GetContents(index_2)),
ContentsId(tabmanager_observer.content()));
EXPECT_FALSE(tabmanager_observer.is_discarded());
// After removing the observer from the TabManager's list, it shouldn't
// receive events anymore.
tab_manager->RemoveObserver(&tabmanager_observer);
EXPECT_TRUE(tab_manager->DiscardTabById(ContentsId(GetContents(index_1)),
DiscardCondition::kProactive));
EXPECT_EQ(4, tabmanager_observer.nb_events());
}
IN_PROC_BROWSER_TEST_F(TabLifetimeObserverTest, OnAutoDiscardableStateChange) {
TabManager* tab_manager = g_browser_process->GetTabManager();
auto* tsm = browser()->tab_strip_model();
set_tab_strip_model(tsm);
// Open two tabs.
OpenURLParams open(GURL(chrome::kChromeUIAboutURL), content::Referrer(),
WindowOpenDisposition::NEW_BACKGROUND_TAB,
ui::PAGE_TRANSITION_TYPED, false);
WebContents* contents = browser()->OpenURL(open);
// Subscribe observer to TabManager's observer list.
MockTabLifetimeObserver observer;
tab_manager->AddObserver(&observer);
// No events initially.
EXPECT_EQ(0, observer.nb_events());
// Should maintain at zero since the default value of the state is true.
tab_manager->SetTabAutoDiscardableState(contents, true);
EXPECT_EQ(0, observer.nb_events());
// Now it has to change.
tab_manager->SetTabAutoDiscardableState(contents, false);
EXPECT_EQ(1, observer.nb_events());
EXPECT_FALSE(observer.is_auto_discardable());
EXPECT_EQ(ContentsId(contents), ContentsId(observer.content()));
// No changes since it's not a new state.
tab_manager->SetTabAutoDiscardableState(contents, false);
EXPECT_EQ(1, observer.nb_events());
// Change it back and we should have another event.
tab_manager->SetTabAutoDiscardableState(contents, true);
EXPECT_EQ(2, observer.nb_events());
EXPECT_TRUE(observer.is_auto_discardable());
EXPECT_EQ(ContentsId(contents), ContentsId(observer.content()));
}
} // namespace resource_coordinator
#endif // defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_LINUX) ||
// defined(OS_CHROMEOS)