Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(120)

Side by Side Diff: chrome/browser/sessions/session_restore_stats_collector_unittest.cc

Issue 1136523004: [Sessions] Add detailed logging of SessionRestore events. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Rebased. Created 5 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "chrome/browser/sessions/session_restore_stats_collector.h"
6
7 #include "base/message_loop/message_loop.h"
8 #include "base/test/simple_test_tick_clock.h"
9 #include "chrome/test/base/testing_profile.h"
10 #include "content/public/browser/notification_service.h"
11 #include "content/public/browser/notification_types.h"
12 #include "content/public/browser/render_widget_host.h"
13 #include "content/public/browser/render_widget_host_view.h"
14 #include "content/public/browser/web_contents.h"
15 #include "content/public/test/test_browser_thread.h"
16 #include "content/public/test/test_web_contents_factory.h"
17 #include "testing/gmock/include/gmock/gmock.h"
18 #include "testing/gtest/include/gtest/gtest.h"
19
20 namespace {
21
22 using testing::_;
23 using testing::AllOf;
24 using testing::Eq;
25 using testing::Field;
26 using testing::Gt;
27 using TabLoaderStats = SessionRestoreStatsCollector::TabLoaderStats;
28 using StatsReportingDelegate =
29 SessionRestoreStatsCollector::StatsReportingDelegate;
30
31 // A mock StatsReportingDelegate. This is used by the unittests to validate the
32 // reporting and lifetime behaviour of the SessionRestoreStatsCollector under
33 // test.
34 class LenientMockStatsReportingDelegate : public StatsReportingDelegate {
35 public:
36 virtual ~LenientMockStatsReportingDelegate() { }
37
38 MOCK_METHOD1(ReportTabLoaderStats, void(const TabLoaderStats&));
sky 2015/06/17 15:33:54 Don't use gmock. See threads in chromium-dev.
chrisha 2015/06/17 17:44:34 Although I'm clearly on the other side in this hol
39 MOCK_METHOD0(ReportTabDeferred, void());
40 MOCK_METHOD0(ReportDeferredTabLoaded, void());
41
42 // This is not part of the StatsReportingDelegate, but an added function that
43 // is invoked by the PassthroughStatsReportingDelegate when it dies. This
44 // allows the tests to be notified the moment the underlying stats collector
45 // terminates itself.
46 MOCK_METHOD0(ReportStatsCollectorDeath, void());
47 };
48 using MockStatsReportingDelegate =
49 testing::StrictMock<LenientMockStatsReportingDelegate>;
50
51 // A pass-through stats reporting delegate. This is used to decouple the
52 // lifetime of the mock reporting delegate from the SessionRestoreStatsCollector
53 // under test. The SessionRestoreStatsCollector has ownership of this delegate,
54 // which will notify the mock delegate upon its death.
55 class PassthroughStatsReportingDelegate : public StatsReportingDelegate {
56 public:
57 PassthroughStatsReportingDelegate() : reporting_delegate_(nullptr) { }
58 virtual ~PassthroughStatsReportingDelegate() {
59 reporting_delegate_->ReportStatsCollectorDeath();
60 }
61
62 void set_reporting_delegate(MockStatsReportingDelegate* reporting_delegate) {
63 reporting_delegate_ = reporting_delegate;
64 }
65
66 void ReportTabLoaderStats(const TabLoaderStats& tab_loader_stats) override {
67 reporting_delegate_->ReportTabLoaderStats(tab_loader_stats);
68 }
69
70 void ReportTabDeferred() override {
71 reporting_delegate_->ReportTabDeferred();
72 }
73
74 void ReportDeferredTabLoaded() override {
75 reporting_delegate_->ReportDeferredTabLoaded();
76 }
77
78 private:
79 MockStatsReportingDelegate* reporting_delegate_;
80 };
81
82 class TestSessionRestoreStatsCollector : public SessionRestoreStatsCollector {
83 public:
84 using SessionRestoreStatsCollector::Observe;
85
86 TestSessionRestoreStatsCollector(
87 scoped_ptr<base::TickClock> tick_clock,
88 scoped_ptr<StatsReportingDelegate> reporting_delegate)
89 : SessionRestoreStatsCollector(
90 tick_clock->NowTicks(),
91 reporting_delegate.Pass()) {
92 set_tick_clock(tick_clock.Pass());
93 }
94
95 private:
96 friend class base::RefCounted<TestSessionRestoreStatsCollector>;
97
98 virtual ~TestSessionRestoreStatsCollector() { }
99
100 base::SimpleTestTickClock* test_tick_clock_;
101 };
102
103 } // namespace
104
105 class SessionRestoreStatsCollectorTest : public testing::Test {
106 public:
107 using RestoredTab = SessionRestoreDelegate::RestoredTab;
108
109 SessionRestoreStatsCollectorTest()
110 : ui_thread_(content::BrowserThread::UI, &message_loop_) {
111 }
112
113 void SetUp() override {
114 test_web_contents_factory_.reset(
115 new content::TestWebContentsFactory);
116
117 // Ownership of the reporting delegate is passed to the
118 // SessionRestoreStatsCollector, but a raw pointer is kept to it so it can
119 // be queried by the test.
120 passthrough_reporting_delegate_ = new PassthroughStatsReportingDelegate();
121
122 // Ownership of this clock is passed to the SessionRestoreStatsCollector.
123 // A raw pointer is kept to it so that it can be modified from the outside.
124 // The unittest must take not to access the clock only while the
125 // SessionRestoreStatsCollector under test is still alive.
126 test_tick_clock_ = new base::SimpleTestTickClock();
127
128 // Create a stats collector, keep a raw pointer to it, and detach from it.
129 // The stats collector will stay alive as long as it has not yet completed
130 // its job, and will clean itself up when done.
131 scoped_refptr<TestSessionRestoreStatsCollector> stats_collector =
132 new TestSessionRestoreStatsCollector(
133 scoped_ptr<base::TickClock>(test_tick_clock_),
134 scoped_ptr<StatsReportingDelegate>(
135 passthrough_reporting_delegate_));
136 stats_collector_ = stats_collector.get();
137 stats_collector = nullptr;
138 }
139
140 void TearDown() override {
141 passthrough_reporting_delegate_ = nullptr;
142 test_tick_clock_ = nullptr;
143 stats_collector_ = nullptr;
144
145 // Clean up any tabs that were generated by the unittest.
146 restored_tabs_.clear();
147 test_web_contents_factory_.reset();
148 }
149
150 // Advances the test clock by 1ms.
151 void Tick() {
152 test_tick_clock_->Advance(base::TimeDelta::FromMilliseconds(1));
153 }
154
155 void Show(size_t tab_index) {
156 restored_tabs_[tab_index].contents()->GetRenderWidgetHostView()->Show();
157 }
158
159 void Hide(size_t tab_index) {
160 restored_tabs_[tab_index].contents()->GetRenderWidgetHostView()->Hide();
161 }
162
163 // Creates a restored tab backed by dummy WebContents/NavigationController/
164 // RenderWidgetHost/RenderWidgetHostView. Returns the index of the restored
165 // tab for future simulation of events.
166 void CreateRestoredTab(bool is_active) {
167 content::WebContents* contents =
168 test_web_contents_factory_->CreateWebContents(&testing_profile_);
169 restored_tabs_.push_back(RestoredTab(contents, is_active, false, false));
170 if (is_active)
171 Show(restored_tabs_.size() - 1);
172 }
173
174 // Helper function for various notification generation.
175 void GenerateControllerNotification(size_t tab_index, int type) {
176 content::WebContents* contents = restored_tabs_[tab_index].contents();
177 content::NavigationController* controller = &contents->GetController();
178 stats_collector_->Observe(
179 type,
180 content::Source<content::NavigationController>(controller),
181 content::NotificationService::NoDetails());
182 }
183
184 // Generates a load start notification for the given tab.
185 void GenerateLoadStart(size_t tab_index) {
186 GenerateControllerNotification(tab_index, content::NOTIFICATION_LOAD_START);
187 }
188
189 // Generates a load stop notification for the given tab.
190 void GenerateLoadStop(size_t tab_index) {
191 GenerateControllerNotification(tab_index, content::NOTIFICATION_LOAD_STOP);
192 }
193
194 // Generates a web contents destroyed notification for the given tab.
195 void GenerateWebContentsDestroyed(size_t tab_index) {
196 content::WebContents* contents = restored_tabs_[tab_index].contents();
197 stats_collector_->Observe(
198 content::NOTIFICATION_WEB_CONTENTS_DESTROYED,
199 content::Source<content::WebContents>(contents),
200 content::NotificationService::NoDetails());
201 }
202
203 // Generates a paint notification for the given tab.
204 void GenerateRenderWidgetHostDidUpdateBackingStore(size_t tab_index) {
205 content::WebContents* contents = restored_tabs_[tab_index].contents();
206 content::RenderWidgetHost* host =
207 contents->GetRenderWidgetHostView()->GetRenderWidgetHost();
208 stats_collector_->Observe(
209 content::NOTIFICATION_RENDER_WIDGET_HOST_DID_UPDATE_BACKING_STORE,
210 content::Source<content::RenderWidgetHost>(host),
211 content::NotificationService::NoDetails());
212 }
213
214 // Defers a tab.
215 void DeferTab(size_t tab_index) {
216 content::WebContents* contents = restored_tabs_[tab_index].contents();
217 content::NavigationController* controller = &contents->GetController();
218 stats_collector_->DeferTab(controller);
219 }
220
221 // Generates mock call expectation to ReportTabLoaderStats, with the given
222 // configuration for the statistics.
223 void ExpectReportTabLoaderStats(
224 MockStatsReportingDelegate* mock_reporting_delegate,
225 size_t tab_count,
226 size_t tabs_loaded,
227 int foreground_tab_first_loaded_ms,
228 int foreground_tab_first_paint_ms,
229 int non_deferred_tabs_loaded_ms,
230 size_t parallel_tab_loads) {
231 EXPECT_CALL(*mock_reporting_delegate, ReportTabLoaderStats(
232 AllOf(Field(&TabLoaderStats::tab_count, Eq(tab_count)),
233 Field(&TabLoaderStats::tabs_loaded, Eq(tabs_loaded)),
234 Field(&TabLoaderStats::foreground_tab_first_loaded,
235 Eq(base::TimeDelta::FromMilliseconds(
236 foreground_tab_first_loaded_ms))),
237 Field(&TabLoaderStats::foreground_tab_first_paint,
238 Eq(base::TimeDelta::FromMilliseconds(
239 foreground_tab_first_paint_ms))),
240 Field(&TabLoaderStats::non_deferred_tabs_loaded,
241 Eq(base::TimeDelta::FromMilliseconds(
242 non_deferred_tabs_loaded_ms))),
243 Field(&TabLoaderStats::parallel_tab_loads,
244 Eq(parallel_tab_loads)))));
245 }
246
247 // Inputs to the stats collector. Reset prior to each test.
248 base::SimpleTestTickClock* test_tick_clock_;
249 std::vector<RestoredTab> restored_tabs_;
250
251 // Infrastructure needed for using the TestWebContentsFactory. These are
252 // initialized once by the fixture and reused across unittests.
253 base::MessageLoop message_loop_;
254 TestingProfile testing_profile_;
255 content::TestBrowserThread ui_thread_;
256
257 // A new web contents factory is generated per test. This automatically cleans
258 // up any tabs created by previous tests.
259 scoped_ptr<content::TestWebContentsFactory> test_web_contents_factory_;
260
261 // These are recreated for each test. The reporting delegate allows the test
262 // to observe the behaviour of the SessionRestoreStatsCollector under test.
263 PassthroughStatsReportingDelegate* passthrough_reporting_delegate_;
264 TestSessionRestoreStatsCollector* stats_collector_;
265 };
266
267 TEST_F(SessionRestoreStatsCollectorTest, SingleTabPaintBeforeLoad) {
268 MockStatsReportingDelegate mock_reporting_delegate;
269 passthrough_reporting_delegate_->set_reporting_delegate(
270 &mock_reporting_delegate);
271
272 CreateRestoredTab(true);
273 stats_collector_->TrackTabs(restored_tabs_);
274
275 Tick(); // 1ms.
276 GenerateRenderWidgetHostDidUpdateBackingStore(0);
277
278 ExpectReportTabLoaderStats(&mock_reporting_delegate, 1, 1, 2, 1, 2, 1);
279 EXPECT_CALL(mock_reporting_delegate, ReportStatsCollectorDeath());
280
281 Tick(); // 2ms.
282 GenerateLoadStop(0);
283 }
284
285 TEST_F(SessionRestoreStatsCollectorTest, SingleTabPaintAfterLoad) {
286 MockStatsReportingDelegate mock_reporting_delegate;
287 passthrough_reporting_delegate_->set_reporting_delegate(
288 &mock_reporting_delegate);
289
290 CreateRestoredTab(true);
291 stats_collector_->TrackTabs(restored_tabs_);
292
293 Tick(); // 1ms.
294 GenerateLoadStop(0);
295
296 ExpectReportTabLoaderStats(&mock_reporting_delegate, 1, 1, 1, 2, 1, 1);
297 EXPECT_CALL(mock_reporting_delegate, ReportStatsCollectorDeath());
298
299 Tick(); // 2ms.
300 GenerateRenderWidgetHostDidUpdateBackingStore(0);
301 }
302
303 TEST_F(SessionRestoreStatsCollectorTest, MultipleTabsLoadSerially) {
304 MockStatsReportingDelegate mock_reporting_delegate;
305 passthrough_reporting_delegate_->set_reporting_delegate(
306 &mock_reporting_delegate);
307
308 CreateRestoredTab(true);
309 CreateRestoredTab(false);
310 CreateRestoredTab(false);
311 stats_collector_->TrackTabs(restored_tabs_);
312
313 // Foreground tab paints then finishes loading.
314 Tick(); // 1ms.
315 GenerateRenderWidgetHostDidUpdateBackingStore(0);
316 Tick(); // 2ms.
317 GenerateLoadStop(0);
318
319 // First background tab starts loading, paints, then finishes loading.
320 Tick(); // 3ms.
321 GenerateLoadStart(1);
322 Tick(); // 4ms.
323 GenerateRenderWidgetHostDidUpdateBackingStore(1);
324 Tick(); // 5ms.
325 GenerateLoadStop(1);
326
327 // Second background tab starts loading, finishes loading, but never paints.
328 Tick(); // 6ms.
329 GenerateLoadStart(2);
330
331 ExpectReportTabLoaderStats(&mock_reporting_delegate, 3, 3, 2, 1, 7, 1);
332 EXPECT_CALL(mock_reporting_delegate, ReportStatsCollectorDeath());
333
334 Tick(); // 7ms.
335 GenerateLoadStop(2);
336 }
337
338 TEST_F(SessionRestoreStatsCollectorTest, MultipleTabsLoadSimultaneously) {
339 MockStatsReportingDelegate mock_reporting_delegate;
340 passthrough_reporting_delegate_->set_reporting_delegate(
341 &mock_reporting_delegate);
342
343 CreateRestoredTab(true);
344 CreateRestoredTab(false);
345 CreateRestoredTab(false);
346 stats_collector_->TrackTabs(restored_tabs_);
347
348 // Foreground tab paints then finishes loading.
349 Tick(); // 1ms.
350 GenerateRenderWidgetHostDidUpdateBackingStore(0);
351 Tick(); // 2ms.
352 GenerateLoadStop(0);
353
354 // Both background tabs start loading at the same time. The first one paints
355 // before finishing loading, the second one paints after finishing loading
356 // (the stats collector never sees the paint event).
357 Tick(); // 3ms.
358 GenerateLoadStart(1);
359 GenerateLoadStart(2);
360 Tick(); // 4ms.
361 GenerateRenderWidgetHostDidUpdateBackingStore(1);
362 Tick(); // 5ms.
363 GenerateLoadStop(1);
364
365 ExpectReportTabLoaderStats(&mock_reporting_delegate, 3, 3, 2, 1, 6, 2);
366 EXPECT_CALL(mock_reporting_delegate, ReportStatsCollectorDeath());
367
368 Tick(); // 6ms.
369 GenerateLoadStop(2);
370 }
371
372 TEST_F(SessionRestoreStatsCollectorTest, DeferredTabs) {
373 MockStatsReportingDelegate mock_reporting_delegate;
374 passthrough_reporting_delegate_->set_reporting_delegate(
375 &mock_reporting_delegate);
376
377 CreateRestoredTab(true);
378 CreateRestoredTab(false);
379 stats_collector_->TrackTabs(restored_tabs_);
380
381 // Foreground tab paints, then the background tab is deferred.
382 Tick(); // 1ms.
383 GenerateRenderWidgetHostDidUpdateBackingStore(0);
384 EXPECT_CALL(mock_reporting_delegate, ReportTabDeferred());
385 DeferTab(1);
386 testing::Mock::VerifyAndClearExpectations(&mock_reporting_delegate);
387
388 // Foreground tab finishes loading and stats get reported.
389 ExpectReportTabLoaderStats(&mock_reporting_delegate, 2, 1, 2, 1, 2, 1);
390 Tick(); // 2ms.
391 GenerateLoadStop(0);
392 testing::Mock::VerifyAndClearExpectations(&mock_reporting_delegate);
393
394 // Background tab starts loading, paints and stops loading. This fires off a
395 // deferred tab loaded notification.
396 Tick(); // 3ms.
397 GenerateLoadStart(1);
398 Tick(); // 4ms.
399 GenerateRenderWidgetHostDidUpdateBackingStore(1);
400 EXPECT_CALL(mock_reporting_delegate, ReportDeferredTabLoaded());
401 EXPECT_CALL(mock_reporting_delegate, ReportStatsCollectorDeath());
402 Tick(); // 5ms.
403 GenerateLoadStop(1);
404 }
405
406 TEST_F(SessionRestoreStatsCollectorTest, FocusSwitchNoForegroundPaintOrLoad) {
407 MockStatsReportingDelegate mock_reporting_delegate;
408 passthrough_reporting_delegate_->set_reporting_delegate(
409 &mock_reporting_delegate);
410
411 CreateRestoredTab(true);
412 stats_collector_->TrackTabs(restored_tabs_);
413
414 // Create another tab and make it the foreground tab. This tab is not actually
415 // being tracked by the SessionRestoreStatsCollector, but its paint events
416 // will be observed.
417 CreateRestoredTab(false);
418 Hide(0);
419 Show(1);
420
421 // Load and paint the restored tab (now the background tab). Don't expect
422 // any calls to the mock as a visible tab paint has not yet been observed.
423 Tick(); // 1ms.
424 GenerateRenderWidgetHostDidUpdateBackingStore(0);
425 Tick(); // 2ms.
426 GenerateLoadStop(0);
427 testing::Mock::VerifyAndClearExpectations(&mock_reporting_delegate);
428
429 // Mark the new foreground tab as having painted. This should cause the
430 // stats to be emitted, but with empty foreground paint and load values.
431 ExpectReportTabLoaderStats(&mock_reporting_delegate, 1, 1, 0, 0, 2, 1);
432 EXPECT_CALL(mock_reporting_delegate, ReportStatsCollectorDeath());
433 Tick(); // 3ms.
434 GenerateRenderWidgetHostDidUpdateBackingStore(1);
435 }
436
437 TEST_F(SessionRestoreStatsCollectorTest, FocusSwitchNoForegroundPaint) {
438 MockStatsReportingDelegate mock_reporting_delegate;
439 passthrough_reporting_delegate_->set_reporting_delegate(
440 &mock_reporting_delegate);
441
442 CreateRestoredTab(true);
443 stats_collector_->TrackTabs(restored_tabs_);
444
445 // Load the foreground tab.
446 Tick(); // 1ms.
447 GenerateLoadStop(0);
448
449 // Create another tab and make it the foreground tab. This tab is not actually
450 // being tracked by the SessionRestoreStatsCollector, but its paint events
451 // will still be observed.
452 CreateRestoredTab(false);
453 Hide(0);
454 Show(1);
455
456 // Load and paint the restored tab (now the background tab). Don't expect
457 // any calls to the mock as a visible tab paint has not yet been observed.
458 Tick(); // 2ms.
459 GenerateRenderWidgetHostDidUpdateBackingStore(0);
460 testing::Mock::VerifyAndClearExpectations(&mock_reporting_delegate);
461
462 // Mark the new foreground tab as having painted. This should cause the
463 // stats to be emitted, but with an empty foreground paint value.
464 ExpectReportTabLoaderStats(&mock_reporting_delegate, 1, 1, 1, 0, 1, 1);
465 EXPECT_CALL(mock_reporting_delegate, ReportStatsCollectorDeath());
466 Tick(); // 3ms.
467 GenerateRenderWidgetHostDidUpdateBackingStore(1);
468 }
469
470 TEST_F(SessionRestoreStatsCollectorTest, LoadingTabDestroyedBeforePaint) {
471 MockStatsReportingDelegate mock_reporting_delegate;
472 passthrough_reporting_delegate_->set_reporting_delegate(
473 &mock_reporting_delegate);
474
475 CreateRestoredTab(true);
476 stats_collector_->TrackTabs(restored_tabs_);
477
478 // Destroy the tab. Expect all timings to be zero.
479 ExpectReportTabLoaderStats(&mock_reporting_delegate, 1, 0, 0, 0, 0, 1);
480 EXPECT_CALL(mock_reporting_delegate, ReportStatsCollectorDeath());
481 GenerateWebContentsDestroyed(0);
482 }
483
484 TEST_F(SessionRestoreStatsCollectorTest, LoadingTabDestroyedAfterPaint) {
485 MockStatsReportingDelegate mock_reporting_delegate;
486 passthrough_reporting_delegate_->set_reporting_delegate(
487 &mock_reporting_delegate);
488
489 CreateRestoredTab(true);
490 stats_collector_->TrackTabs(restored_tabs_);
491
492 Tick(); // 1 ms.
493 GenerateRenderWidgetHostDidUpdateBackingStore(0);
494
495 // Destroy the tab. Expect both load timings to be zero.
496 ExpectReportTabLoaderStats(&mock_reporting_delegate, 1, 0, 0, 1, 0, 1);
497 EXPECT_CALL(mock_reporting_delegate, ReportStatsCollectorDeath());
498 GenerateWebContentsDestroyed(0);
499 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698