blob: 538f9720acc6994b601b07fdc6bd8d7fcf3f3478 [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 "chrome/browser/sessions/session_restore_stats_collector.h"
#include "base/message_loop/message_loop.h"
#include "base/test/simple_test_tick_clock.h"
#include "chrome/test/base/testing_profile.h"
#include "content/public/browser/notification_service.h"
#include "content/public/browser/notification_types.h"
#include "content/public/browser/render_widget_host.h"
#include "content/public/browser/render_widget_host_view.h"
#include "content/public/browser/web_contents.h"
#include "content/public/test/test_browser_thread.h"
#include "content/public/test/test_web_contents_factory.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace {
using TabLoaderStats = SessionRestoreStatsCollector::TabLoaderStats;
using StatsReportingDelegate =
SessionRestoreStatsCollector::StatsReportingDelegate;
// A mock StatsReportingDelegate. This is used by the unittests to validate the
// reporting and lifetime behaviour of the SessionRestoreStatsCollector under
// test.
class MockStatsReportingDelegate : public StatsReportingDelegate {
public:
MockStatsReportingDelegate()
: report_tab_loader_stats_call_count_(0u),
report_tab_deferred_call_count_(0u),
report_deferred_tab_loaded_call_count_(0u),
report_stats_collector_death_call_count_(0u) {}
~MockStatsReportingDelegate() override { EnsureNoUnexpectedCalls(); }
void ReportTabLoaderStats(const TabLoaderStats& stats) override {
report_tab_loader_stats_call_count_++;
tab_loader_stats_ = stats;
}
void ReportTabDeferred() override { report_tab_deferred_call_count_++; }
void ReportDeferredTabLoaded() override {
report_deferred_tab_loaded_call_count_++;
}
// This is not part of the StatsReportingDelegate, but an added function that
// is invoked by the PassthroughStatsReportingDelegate when it dies. This
// allows the tests to be notified the moment the underlying stats collector
// terminates itself.
void ReportStatsCollectorDeath() {
report_stats_collector_death_call_count_++;
}
void ExpectReportTabLoaderStatsCalled(size_t tab_count,
size_t tabs_deferred,
size_t tabs_load_started,
size_t tabs_loaded,
int foreground_tab_first_loaded_ms,
int foreground_tab_first_paint_ms,
int non_deferred_tabs_loaded_ms,
size_t parallel_tab_loads) {
EXPECT_LT(0u, report_tab_loader_stats_call_count_);
report_tab_loader_stats_call_count_--;
EXPECT_EQ(tab_count, tab_loader_stats_.tab_count);
EXPECT_EQ(tabs_deferred, tab_loader_stats_.tabs_deferred);
EXPECT_EQ(tabs_load_started, tab_loader_stats_.tabs_load_started);
EXPECT_EQ(tabs_loaded, tab_loader_stats_.tabs_loaded);
EXPECT_EQ(base::TimeDelta::FromMilliseconds(foreground_tab_first_loaded_ms),
tab_loader_stats_.foreground_tab_first_loaded);
EXPECT_EQ(base::TimeDelta::FromMilliseconds(foreground_tab_first_paint_ms),
tab_loader_stats_.foreground_tab_first_paint);
EXPECT_EQ(base::TimeDelta::FromMilliseconds(non_deferred_tabs_loaded_ms),
tab_loader_stats_.non_deferred_tabs_loaded);
EXPECT_EQ(parallel_tab_loads, tab_loader_stats_.parallel_tab_loads);
}
void ExpectReportTabDeferredCalled() {
EXPECT_LT(0u, report_tab_deferred_call_count_);
report_tab_deferred_call_count_--;
}
void ExpectReportDeferredTabLoadedCalled() {
EXPECT_LT(0u, report_deferred_tab_loaded_call_count_);
report_deferred_tab_loaded_call_count_--;
}
void ExpectReportStatsCollectorDeathCalled() {
EXPECT_LT(0u, report_stats_collector_death_call_count_);
report_stats_collector_death_call_count_--;
}
void EnsureNoUnexpectedCalls() {
EXPECT_EQ(0u, report_tab_loader_stats_call_count_);
EXPECT_EQ(0u, report_tab_deferred_call_count_);
EXPECT_EQ(0u, report_deferred_tab_loaded_call_count_);
EXPECT_EQ(0u, report_stats_collector_death_call_count_);
report_tab_loader_stats_call_count_ = 0u;
report_tab_deferred_call_count_ = 0u;
report_deferred_tab_loaded_call_count_ = 0u;
report_stats_collector_death_call_count_ = 0u;
tab_loader_stats_ = TabLoaderStats();
}
private:
size_t report_tab_loader_stats_call_count_;
size_t report_tab_deferred_call_count_;
size_t report_deferred_tab_loaded_call_count_;
size_t report_stats_collector_death_call_count_;
TabLoaderStats tab_loader_stats_;
DISALLOW_COPY_AND_ASSIGN(MockStatsReportingDelegate);
};
// A pass-through stats reporting delegate. This is used to decouple the
// lifetime of the mock reporting delegate from the SessionRestoreStatsCollector
// under test. The SessionRestoreStatsCollector has ownership of this delegate,
// which will notify the mock delegate upon its death.
class PassthroughStatsReportingDelegate : public StatsReportingDelegate {
public:
PassthroughStatsReportingDelegate() : reporting_delegate_(nullptr) {}
~PassthroughStatsReportingDelegate() override {
reporting_delegate_->ReportStatsCollectorDeath();
}
void set_reporting_delegate(MockStatsReportingDelegate* reporting_delegate) {
reporting_delegate_ = reporting_delegate;
}
void ReportTabLoaderStats(const TabLoaderStats& tab_loader_stats) override {
reporting_delegate_->ReportTabLoaderStats(tab_loader_stats);
}
void ReportTabDeferred() override {
reporting_delegate_->ReportTabDeferred();
}
void ReportDeferredTabLoaded() override {
reporting_delegate_->ReportDeferredTabLoaded();
}
private:
MockStatsReportingDelegate* reporting_delegate_;
DISALLOW_COPY_AND_ASSIGN(PassthroughStatsReportingDelegate);
};
} // namespace
class TestSessionRestoreStatsCollector : public SessionRestoreStatsCollector {
public:
using SessionRestoreStatsCollector::Observe;
TestSessionRestoreStatsCollector(
scoped_ptr<base::TickClock> tick_clock,
scoped_ptr<StatsReportingDelegate> reporting_delegate)
: SessionRestoreStatsCollector(tick_clock->NowTicks(),
reporting_delegate.Pass()) {
set_tick_clock(tick_clock.Pass());
}
private:
friend class base::RefCounted<TestSessionRestoreStatsCollector>;
~TestSessionRestoreStatsCollector() override {}
base::SimpleTestTickClock* test_tick_clock_;
DISALLOW_COPY_AND_ASSIGN(TestSessionRestoreStatsCollector);
};
class SessionRestoreStatsCollectorTest : public testing::Test {
public:
using RestoredTab = SessionRestoreDelegate::RestoredTab;
SessionRestoreStatsCollectorTest()
: ui_thread_(content::BrowserThread::UI, &message_loop_) {}
void SetUp() override {
test_web_contents_factory_.reset(new content::TestWebContentsFactory);
// Ownership of the reporting delegate is passed to the
// SessionRestoreStatsCollector, but a raw pointer is kept to it so it can
// be queried by the test.
passthrough_reporting_delegate_ = new PassthroughStatsReportingDelegate();
// Ownership of this clock is passed to the SessionRestoreStatsCollector.
// A raw pointer is kept to it so that it can be modified from the outside.
// The unittest must take care to access the clock only while the
// SessionRestoreStatsCollector under test is still alive.
test_tick_clock_ = new base::SimpleTestTickClock();
// Create a stats collector, keep a raw pointer to it, and detach from it.
// The stats collector will stay alive as long as it has not yet completed
// its job, and will clean itself up when done.
scoped_refptr<TestSessionRestoreStatsCollector> stats_collector =
new TestSessionRestoreStatsCollector(
scoped_ptr<base::TickClock>(test_tick_clock_),
scoped_ptr<StatsReportingDelegate>(
passthrough_reporting_delegate_));
stats_collector_ = stats_collector.get();
stats_collector = nullptr;
}
void TearDown() override {
passthrough_reporting_delegate_ = nullptr;
test_tick_clock_ = nullptr;
stats_collector_ = nullptr;
// Clean up any tabs that were generated by the unittest.
restored_tabs_.clear();
test_web_contents_factory_.reset();
}
// Advances the test clock by 1ms.
void Tick() {
test_tick_clock_->Advance(base::TimeDelta::FromMilliseconds(1));
}
void Show(size_t tab_index) {
restored_tabs_[tab_index].contents()->GetRenderWidgetHostView()->Show();
}
void Hide(size_t tab_index) {
restored_tabs_[tab_index].contents()->GetRenderWidgetHostView()->Hide();
}
// Creates a restored tab backed by dummy WebContents/NavigationController/
// RenderWidgetHost/RenderWidgetHostView. Returns the index of the restored
// tab for future simulation of events.
void CreateRestoredTab(bool is_active) {
content::WebContents* contents =
test_web_contents_factory_->CreateWebContents(&testing_profile_);
restored_tabs_.push_back(RestoredTab(contents, is_active, false, false));
if (is_active)
Show(restored_tabs_.size() - 1);
}
// Helper function for various notification generation.
void GenerateControllerNotification(size_t tab_index, int type) {
content::WebContents* contents = restored_tabs_[tab_index].contents();
content::NavigationController* controller = &contents->GetController();
stats_collector_->Observe(
type, content::Source<content::NavigationController>(controller),
content::NotificationService::NoDetails());
}
// Generates a load start notification for the given tab.
void GenerateLoadStart(size_t tab_index) {
GenerateControllerNotification(tab_index, content::NOTIFICATION_LOAD_START);
}
// Generates a load stop notification for the given tab.
void GenerateLoadStop(size_t tab_index) {
GenerateControllerNotification(tab_index, content::NOTIFICATION_LOAD_STOP);
}
// Generates a web contents destroyed notification for the given tab.
void GenerateWebContentsDestroyed(size_t tab_index) {
content::WebContents* contents = restored_tabs_[tab_index].contents();
stats_collector_->Observe(content::NOTIFICATION_WEB_CONTENTS_DESTROYED,
content::Source<content::WebContents>(contents),
content::NotificationService::NoDetails());
}
// Generates a paint notification for the given tab.
void GenerateRenderWidgetHostDidUpdateBackingStore(size_t tab_index) {
content::WebContents* contents = restored_tabs_[tab_index].contents();
content::RenderWidgetHost* host =
contents->GetRenderWidgetHostView()->GetRenderWidgetHost();
stats_collector_->Observe(
content::NOTIFICATION_RENDER_WIDGET_HOST_DID_UPDATE_BACKING_STORE,
content::Source<content::RenderWidgetHost>(host),
content::NotificationService::NoDetails());
}
// Defers a tab.
void DeferTab(size_t tab_index) {
content::WebContents* contents = restored_tabs_[tab_index].contents();
content::NavigationController* controller = &contents->GetController();
stats_collector_->DeferTab(controller);
}
// Inputs to the stats collector. Reset prior to each test.
base::SimpleTestTickClock* test_tick_clock_;
std::vector<RestoredTab> restored_tabs_;
// Infrastructure needed for using the TestWebContentsFactory. These are
// initialized once by the fixture and reused across unittests.
base::MessageLoop message_loop_;
TestingProfile testing_profile_;
content::TestBrowserThread ui_thread_;
// A new web contents factory is generated per test. This automatically cleans
// up any tabs created by previous tests.
scoped_ptr<content::TestWebContentsFactory> test_web_contents_factory_;
// These are recreated for each test. The reporting delegate allows the test
// to observe the behaviour of the SessionRestoreStatsCollector under test.
PassthroughStatsReportingDelegate* passthrough_reporting_delegate_;
TestSessionRestoreStatsCollector* stats_collector_;
private:
DISALLOW_COPY_AND_ASSIGN(SessionRestoreStatsCollectorTest);
};
TEST_F(SessionRestoreStatsCollectorTest, SingleTabPaintBeforeLoad) {
MockStatsReportingDelegate mock_reporting_delegate;
passthrough_reporting_delegate_->set_reporting_delegate(
&mock_reporting_delegate);
CreateRestoredTab(true);
stats_collector_->TrackTabs(restored_tabs_);
mock_reporting_delegate.EnsureNoUnexpectedCalls();
Tick(); // 1ms.
GenerateRenderWidgetHostDidUpdateBackingStore(0);
mock_reporting_delegate.EnsureNoUnexpectedCalls();
Tick(); // 2ms.
GenerateLoadStop(0);
mock_reporting_delegate.ExpectReportTabLoaderStatsCalled(1, 0, 1, 1, 2, 1, 2,
1);
mock_reporting_delegate.ExpectReportStatsCollectorDeathCalled();
}
TEST_F(SessionRestoreStatsCollectorTest, SingleTabPaintAfterLoad) {
MockStatsReportingDelegate mock_reporting_delegate;
passthrough_reporting_delegate_->set_reporting_delegate(
&mock_reporting_delegate);
CreateRestoredTab(true);
stats_collector_->TrackTabs(restored_tabs_);
Tick(); // 1ms.
GenerateLoadStop(0);
mock_reporting_delegate.EnsureNoUnexpectedCalls();
Tick(); // 2ms.
GenerateRenderWidgetHostDidUpdateBackingStore(0);
mock_reporting_delegate.ExpectReportTabLoaderStatsCalled(1, 0, 1, 1, 1, 2, 1,
1);
mock_reporting_delegate.ExpectReportStatsCollectorDeathCalled();
}
TEST_F(SessionRestoreStatsCollectorTest, MultipleTabsLoadSerially) {
MockStatsReportingDelegate mock_reporting_delegate;
passthrough_reporting_delegate_->set_reporting_delegate(
&mock_reporting_delegate);
CreateRestoredTab(true);
CreateRestoredTab(false);
CreateRestoredTab(false);
stats_collector_->TrackTabs(restored_tabs_);
mock_reporting_delegate.EnsureNoUnexpectedCalls();
// Foreground tab paints then finishes loading.
Tick(); // 1ms.
GenerateRenderWidgetHostDidUpdateBackingStore(0);
mock_reporting_delegate.EnsureNoUnexpectedCalls();
Tick(); // 2ms.
GenerateLoadStop(0);
mock_reporting_delegate.EnsureNoUnexpectedCalls();
// First background tab starts loading, paints, then finishes loading.
Tick(); // 3ms.
GenerateLoadStart(1);
mock_reporting_delegate.EnsureNoUnexpectedCalls();
Tick(); // 4ms.
GenerateRenderWidgetHostDidUpdateBackingStore(1);
mock_reporting_delegate.EnsureNoUnexpectedCalls();
Tick(); // 5ms.
GenerateLoadStop(1);
mock_reporting_delegate.EnsureNoUnexpectedCalls();
// Second background tab starts loading, finishes loading, but never paints.
Tick(); // 6ms.
GenerateLoadStart(2);
mock_reporting_delegate.EnsureNoUnexpectedCalls();
Tick(); // 7ms.
GenerateLoadStop(2);
mock_reporting_delegate.ExpectReportTabLoaderStatsCalled(3, 0, 3, 3, 2, 1, 7,
1);
mock_reporting_delegate.ExpectReportStatsCollectorDeathCalled();
mock_reporting_delegate.EnsureNoUnexpectedCalls();
}
TEST_F(SessionRestoreStatsCollectorTest, MultipleTabsLoadSimultaneously) {
MockStatsReportingDelegate mock_reporting_delegate;
passthrough_reporting_delegate_->set_reporting_delegate(
&mock_reporting_delegate);
CreateRestoredTab(true);
CreateRestoredTab(false);
CreateRestoredTab(false);
stats_collector_->TrackTabs(restored_tabs_);
mock_reporting_delegate.EnsureNoUnexpectedCalls();
// Foreground tab paints then finishes loading.
Tick(); // 1ms.
GenerateRenderWidgetHostDidUpdateBackingStore(0);
mock_reporting_delegate.EnsureNoUnexpectedCalls();
Tick(); // 2ms.
GenerateLoadStop(0);
mock_reporting_delegate.EnsureNoUnexpectedCalls();
// Both background tabs start loading at the same time. The first one paints
// before finishing loading, the second one paints after finishing loading
// (the stats collector never sees the paint event).
Tick(); // 3ms.
GenerateLoadStart(1);
mock_reporting_delegate.EnsureNoUnexpectedCalls();
GenerateLoadStart(2);
mock_reporting_delegate.EnsureNoUnexpectedCalls();
Tick(); // 4ms.
GenerateRenderWidgetHostDidUpdateBackingStore(1);
mock_reporting_delegate.EnsureNoUnexpectedCalls();
Tick(); // 5ms.
GenerateLoadStop(1);
mock_reporting_delegate.EnsureNoUnexpectedCalls();
Tick(); // 6ms.
GenerateLoadStop(2);
mock_reporting_delegate.ExpectReportTabLoaderStatsCalled(3, 0, 3, 3, 2, 1, 6,
2);
mock_reporting_delegate.ExpectReportStatsCollectorDeathCalled();
mock_reporting_delegate.EnsureNoUnexpectedCalls();
}
TEST_F(SessionRestoreStatsCollectorTest, DeferredTabs) {
MockStatsReportingDelegate mock_reporting_delegate;
passthrough_reporting_delegate_->set_reporting_delegate(
&mock_reporting_delegate);
CreateRestoredTab(true);
CreateRestoredTab(false);
stats_collector_->TrackTabs(restored_tabs_);
mock_reporting_delegate.EnsureNoUnexpectedCalls();
// Foreground tab paints, then the background tab is deferred.
Tick(); // 1ms.
GenerateRenderWidgetHostDidUpdateBackingStore(0);
mock_reporting_delegate.EnsureNoUnexpectedCalls();
DeferTab(1);
mock_reporting_delegate.ExpectReportTabDeferredCalled();
mock_reporting_delegate.EnsureNoUnexpectedCalls();
// Foreground tab finishes loading and stats get reported.
Tick(); // 2ms.
GenerateLoadStop(0);
mock_reporting_delegate.ExpectReportTabLoaderStatsCalled(2, 1, 1, 1, 2, 1, 2,
1);
mock_reporting_delegate.EnsureNoUnexpectedCalls();
// Background tab starts loading, paints and stops loading. This fires off a
// deferred tab loaded notification.
Tick(); // 3ms.
GenerateLoadStart(1);
mock_reporting_delegate.EnsureNoUnexpectedCalls();
Tick(); // 4ms.
GenerateRenderWidgetHostDidUpdateBackingStore(1);
mock_reporting_delegate.EnsureNoUnexpectedCalls();
Tick(); // 5ms.
GenerateLoadStop(1);
mock_reporting_delegate.ExpectReportDeferredTabLoadedCalled();
mock_reporting_delegate.ExpectReportStatsCollectorDeathCalled();
mock_reporting_delegate.EnsureNoUnexpectedCalls();
}
TEST_F(SessionRestoreStatsCollectorTest, FocusSwitchNoForegroundPaintOrLoad) {
MockStatsReportingDelegate mock_reporting_delegate;
passthrough_reporting_delegate_->set_reporting_delegate(
&mock_reporting_delegate);
CreateRestoredTab(true);
stats_collector_->TrackTabs(restored_tabs_);
mock_reporting_delegate.EnsureNoUnexpectedCalls();
// Create another tab and make it the foreground tab. This tab is not actually
// being tracked by the SessionRestoreStatsCollector, but its paint events
// will be observed.
CreateRestoredTab(false);
Hide(0);
Show(1);
// Load and paint the restored tab (now the background tab). Don't expect
// any calls to the mock as a visible tab paint has not yet been observed.
Tick(); // 1ms.
GenerateRenderWidgetHostDidUpdateBackingStore(0);
mock_reporting_delegate.EnsureNoUnexpectedCalls();
Tick(); // 2ms.
GenerateLoadStop(0);
mock_reporting_delegate.EnsureNoUnexpectedCalls();
// Mark the new foreground tab as having painted. This should cause the
// stats to be emitted, but with empty foreground paint and load values.
Tick(); // 3ms.
GenerateRenderWidgetHostDidUpdateBackingStore(1);
mock_reporting_delegate.ExpectReportTabLoaderStatsCalled(1, 0, 1, 1, 0, 0, 2,
1);
mock_reporting_delegate.ExpectReportStatsCollectorDeathCalled();
mock_reporting_delegate.EnsureNoUnexpectedCalls();
}
TEST_F(SessionRestoreStatsCollectorTest, FocusSwitchNoForegroundPaint) {
MockStatsReportingDelegate mock_reporting_delegate;
passthrough_reporting_delegate_->set_reporting_delegate(
&mock_reporting_delegate);
CreateRestoredTab(true);
stats_collector_->TrackTabs(restored_tabs_);
mock_reporting_delegate.EnsureNoUnexpectedCalls();
// Load the foreground tab.
Tick(); // 1ms.
GenerateLoadStop(0);
mock_reporting_delegate.EnsureNoUnexpectedCalls();
// Create another tab and make it the foreground tab. This tab is not actually
// being tracked by the SessionRestoreStatsCollector, but its paint events
// will still be observed.
CreateRestoredTab(false);
Hide(0);
Show(1);
// Load and paint the restored tab (now the background tab). Don't expect
// any calls to the mock as a visible tab paint has not yet been observed.
Tick(); // 2ms.
GenerateRenderWidgetHostDidUpdateBackingStore(0);
mock_reporting_delegate.EnsureNoUnexpectedCalls();
// Mark the new foreground tab as having painted. This should cause the
// stats to be emitted, but with an empty foreground paint value.
Tick(); // 3ms.
GenerateRenderWidgetHostDidUpdateBackingStore(1);
mock_reporting_delegate.ExpectReportTabLoaderStatsCalled(1, 0, 1, 1, 1, 0, 1,
1);
mock_reporting_delegate.ExpectReportStatsCollectorDeathCalled();
mock_reporting_delegate.EnsureNoUnexpectedCalls();
}
TEST_F(SessionRestoreStatsCollectorTest, LoadingTabDestroyedBeforePaint) {
MockStatsReportingDelegate mock_reporting_delegate;
passthrough_reporting_delegate_->set_reporting_delegate(
&mock_reporting_delegate);
CreateRestoredTab(true);
stats_collector_->TrackTabs(restored_tabs_);
mock_reporting_delegate.EnsureNoUnexpectedCalls();
// Destroy the tab. Expect all timings to be zero.
GenerateWebContentsDestroyed(0);
mock_reporting_delegate.ExpectReportTabLoaderStatsCalled(1, 0, 1, 0, 0, 0, 0,
1);
mock_reporting_delegate.ExpectReportStatsCollectorDeathCalled();
mock_reporting_delegate.EnsureNoUnexpectedCalls();
}
TEST_F(SessionRestoreStatsCollectorTest, LoadingTabDestroyedAfterPaint) {
MockStatsReportingDelegate mock_reporting_delegate;
passthrough_reporting_delegate_->set_reporting_delegate(
&mock_reporting_delegate);
CreateRestoredTab(true);
stats_collector_->TrackTabs(restored_tabs_);
mock_reporting_delegate.EnsureNoUnexpectedCalls();
Tick(); // 1 ms.
GenerateRenderWidgetHostDidUpdateBackingStore(0);
mock_reporting_delegate.EnsureNoUnexpectedCalls();
// Destroy the tab. Expect both load timings to be zero.
GenerateWebContentsDestroyed(0);
mock_reporting_delegate.ExpectReportTabLoaderStatsCalled(1, 0, 1, 0, 0, 1, 0,
1);
mock_reporting_delegate.ExpectReportStatsCollectorDeathCalled();
mock_reporting_delegate.EnsureNoUnexpectedCalls();
}
TEST_F(SessionRestoreStatsCollectorTest, BrowseAwayBeforePaint) {
MockStatsReportingDelegate mock_reporting_delegate;
passthrough_reporting_delegate_->set_reporting_delegate(
&mock_reporting_delegate);
CreateRestoredTab(true);
stats_collector_->TrackTabs(restored_tabs_);
mock_reporting_delegate.EnsureNoUnexpectedCalls();
// Load the tab.
Tick(); // 1 ms.
GenerateLoadStop(0);
mock_reporting_delegate.EnsureNoUnexpectedCalls();
// Reload the tab. Expect the paint timing to be zero.
Tick(); // 2 ms.
GenerateLoadStart(0);
mock_reporting_delegate.ExpectReportTabLoaderStatsCalled(1, 0, 1, 1, 1, 0, 1,
1);
mock_reporting_delegate.ExpectReportStatsCollectorDeathCalled();
mock_reporting_delegate.EnsureNoUnexpectedCalls();
}
TEST_F(SessionRestoreStatsCollectorTest, DiscardDeferredTabs) {
MockStatsReportingDelegate mock_reporting_delegate;
passthrough_reporting_delegate_->set_reporting_delegate(
&mock_reporting_delegate);
CreateRestoredTab(true);
CreateRestoredTab(false);
stats_collector_->TrackTabs(restored_tabs_);
mock_reporting_delegate.EnsureNoUnexpectedCalls();
// Defer the background tab.
Tick(); // 1 ms.
DeferTab(1);
mock_reporting_delegate.ExpectReportTabDeferredCalled();
mock_reporting_delegate.EnsureNoUnexpectedCalls();
// Discard the foreground tab. The stats tab loader stats should be reported
// with all zero timings.
Tick(); // 2 ms.
GenerateWebContentsDestroyed(0);
mock_reporting_delegate.ExpectReportTabLoaderStatsCalled(2, 1, 1, 0, 0, 0, 0,
1);
mock_reporting_delegate.EnsureNoUnexpectedCalls();
// Destroy the background tab. The collector should release itself.
Tick(); // 3 ms.
GenerateWebContentsDestroyed(1);
mock_reporting_delegate.ExpectReportStatsCollectorDeathCalled();
mock_reporting_delegate.EnsureNoUnexpectedCalls();
}