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

Side by Side Diff: ios/chrome/browser/metrics/tab_usage_recorder_egtest.mm

Issue 2585233003: Upstream Chrome on iOS source code [2/11]. (Closed)
Patch Set: Created 4 years 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 2016 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 #import <EarlGrey/EarlGrey.h>
6 #import <XCTest/XCTest.h>
7
8 #include "base/mac/bind_objc_block.h"
9 #include "base/memory/ptr_util.h"
10 #include "base/strings/stringprintf.h"
11 #include "base/strings/sys_string_conversions.h"
12 #include "base/strings/utf_string_conversions.h"
13 #import "base/test/ios/wait_util.h"
14 #include "components/strings/grit/components_strings.h"
15 #include "ios/chrome/browser/experimental_flags.h"
16 #import "ios/chrome/browser/metrics/tab_usage_recorder.h"
17 #import "ios/chrome/browser/ui/settings/privacy_collection_view_controller.h"
18 #import "ios/chrome/browser/ui/settings/settings_collection_view_controller.h"
19 #import "ios/chrome/browser/ui/toolbar/toolbar_controller.h"
20 #import "ios/chrome/browser/ui/tools_menu/tools_menu_view_controller.h"
21 #include "ios/chrome/browser/ui/ui_util.h"
22 #import "ios/chrome/browser/ui/uikit_ui_util.h"
23 #include "ios/chrome/grit/ios_strings.h"
24 #import "ios/chrome/test/app/chrome_test_util.h"
25 #import "ios/chrome/test/app/histogram_test_util.h"
26 #include "ios/chrome/test/app/navigation_test_util.h"
27 #import "ios/chrome/test/app/tab_test_util.h"
28 #include "ios/chrome/test/app/web_view_interaction_test_util.h"
29 #import "ios/chrome/test/earl_grey/chrome_assertions.h"
30 #import "ios/chrome/test/earl_grey/chrome_earl_grey.h"
31 #import "ios/chrome/test/earl_grey/chrome_earl_grey_ui.h"
32 #import "ios/chrome/test/earl_grey/chrome_matchers.h"
33 #import "ios/chrome/test/earl_grey/chrome_test_case.h"
34 #import "ios/testing/wait_util.h"
35 #import "ios/web/public/test/http_server.h"
36 #import "ios/web/public/test/http_server_util.h"
37 #include "ios/web/public/test/response_providers/delayed_response_provider.h"
38 #include "ios/web/public/test/response_providers/html_response_provider.h"
39 #include "ui/base/l10n/l10n_util.h"
40 #include "ui/base/l10n/l10n_util_mac.h"
41
42 namespace {
43
44 const char kTestUrl1[] =
45 "http://ios/testing/data/http_server_files/memory_usage.html";
46 const char kURL1FirstWord[] = "Page";
47 const char kTestUrl2[] =
48 "http://ios/testing/data/http_server_files/fullscreen.html";
49 const char kURL2FirstWord[] = "Rugby";
50 const char kClearPageScript[] = "document.body.innerHTML='';";
51
52 // The delay to use to serve slow URLs.
53 const CGFloat kSlowURLDelay = 3;
54
55 // The delay to wait for an element to appear before tapping on it.
56 const CGFloat kWaitElementTimeout = 3;
57
58 void ResetTabUsageRecorder() {
59 GREYAssertTrue(chrome_test_util::ResetTabUsageRecorder(),
60 @"Fail to reset the TabUsageRecorder");
61 }
62
63 // Wait until |matcher| is accessible (not nil).
64 void Wait(id<GREYMatcher> matcher, NSString* name) {
65 ConditionBlock condition = ^{
66 NSError* error = nil;
67 [[EarlGrey selectElementWithMatcher:matcher] assertWithMatcher:grey_notNil()
68 error:&error];
69 return error == nil;
70 };
71 GREYAssert(
72 testing::WaitUntilConditionOrTimeout(kWaitElementTimeout, condition),
73 [NSString stringWithFormat:@"Waiting for matcher %@ failed.", name]);
74 }
75
76 // Wait until |matcher| is accessible (not nil) and tap on it.
77 void WaitAndTap(id<GREYMatcher> matcher, NSString* name) {
78 Wait(matcher, name);
79 [[EarlGrey selectElementWithMatcher:matcher] performAction:grey_tap()];
80 }
81
82 // Creates a new main tab and load |url|. Wait until |word| is visible on the
83 // page.
84 void NewMainTabWithURL(const GURL& url, const std::string& word) {
85 int number_of_tabs = chrome_test_util::GetMainTabCount();
86 chrome_test_util::OpenNewTab();
87 [ChromeEarlGrey loadURL:url];
88 [[EarlGrey
89 selectElementWithMatcher:chrome_test_util::webViewContainingText(word)]
90 assertWithMatcher:grey_notNil()];
91 chrome_test_util::AssertMainTabCount(number_of_tabs + 1);
92 }
93
94 // Opens 2 new tabs with different URLs.
95 void OpenTwoTabs() {
96 chrome_test_util::CloseAllTabsInCurrentMode();
97
98 const GURL url1 = web::test::HttpServer::MakeUrl(kTestUrl1);
99 const GURL url2 = web::test::HttpServer::MakeUrl(kTestUrl2);
100 NewMainTabWithURL(url1, kURL1FirstWord);
101 NewMainTabWithURL(url2, kURL2FirstWord);
102 }
103
104 // Opens a new main tab using the UI. This method is using ad-hoc
105 // synchronization.
106 void OpenNewMainTabUsingUIUnsynced() {
107 int nb_main_tab = chrome_test_util::GetMainTabCount();
108 id<GREYMatcher> tool_menu_matcher =
109 grey_accessibilityID(kToolbarToolsMenuButtonIdentifier);
110 WaitAndTap(tool_menu_matcher, @"Tool menu");
111 id<GREYMatcher> new_main_tab_button_matcher =
112 grey_accessibilityID(kToolsMenuNewTabId);
113 WaitAndTap(new_main_tab_button_matcher, @"New tab button");
114
115 chrome_test_util::AssertMainTabCount(nb_main_tab + 1);
116 }
117
118 // Opens a new incognito tab using the UI and evicts any main tab model tabs.
119 void OpenNewIncognitoTabUsingUIAndEvictMainTabs() {
120 int nb_incognito_tab = chrome_test_util::GetIncognitoTabCount();
121 [ChromeEarlGreyUI openToolsMenu];
122 id<GREYMatcher> new_incognito_tab_button_matcher =
123 grey_accessibilityID(kToolsMenuNewIncognitoTabId);
124 [[EarlGrey selectElementWithMatcher:new_incognito_tab_button_matcher]
125 performAction:grey_tap()];
126 chrome_test_util::AssertIncognitoTabCount(nb_incognito_tab + 1);
127
128 chrome_test_util::EvictOtherTabModelTabs();
129 }
130
131 // Closes a tab in the current tab model. Synchronize on tab number afterwards.
132 void CloseTabAtIndexAndSync(NSUInteger i) {
133 NSUInteger nb_main_tab = chrome_test_util::GetMainTabCount();
134 chrome_test_util::CloseTabAtIndex(i);
135 ConditionBlock condition = ^{
136 return chrome_test_util::GetMainTabCount() == (nb_main_tab - 1);
137 };
138 GREYAssert(
139 testing::WaitUntilConditionOrTimeout(kWaitElementTimeout, condition),
140 @"Waiting for tab to close");
141 }
142
143 // Closes the tabs switcher.
144 void CloseTabSwitcher() {
145 id<GREYMatcher> matcher = chrome_test_util::buttonWithAccessibilityLabelId(
146 IDS_IOS_TAB_STRIP_LEAVE_TAB_SWITCHER);
147 [[EarlGrey selectElementWithMatcher:matcher] performAction:grey_tap()];
148 }
149
150 // Swithches to normal mode using swith button (iPad) or stack view (iPhone).
151 // Assumes current mode is Incognito.
152 void SwitchToNormalMode() {
153 GREYAssertTrue(chrome_test_util::IsIncognitoMode(),
154 @"Switching to normal mode is only allowed from Incognito.");
155 if (IsIPadIdiom()) {
156 if (experimental_flags::IsTabSwitcherEnabled()) {
157 // Enter the tab switcher.
158 id<GREYMatcher> tabSwitcherEnterButton =
159 grey_accessibilityLabel(l10n_util::GetNSStringWithFixup(
160 IDS_IOS_TAB_STRIP_ENTER_TAB_SWITCHER));
161 [[EarlGrey selectElementWithMatcher:tabSwitcherEnterButton]
162 performAction:grey_tap()];
163
164 // Select the non incognito panel.
165 id<GREYMatcher> tabSwitcherHeaderPanelButton =
166 grey_accessibilityLabel(l10n_util::GetNSStringWithFixup(
167 IDS_IOS_TAB_SWITCHER_HEADER_NON_INCOGNITO_TABS));
168 [[EarlGrey selectElementWithMatcher:tabSwitcherHeaderPanelButton]
169 performAction:grey_tap()];
170
171 // Leave the tab switcher.
172 CloseTabSwitcher();
173 } else {
174 [[EarlGrey selectElementWithMatcher:
175 chrome_test_util::buttonWithAccessibilityLabelId(
176 IDS_IOS_SWITCH_BROWSER_MODE_LEAVE_INCOGNITO)]
177 performAction:grey_tap()];
178 }
179 } else {
180 [[EarlGrey selectElementWithMatcher:
181 chrome_test_util::buttonWithAccessibilityLabelId(
182 IDS_IOS_TOOLBAR_SHOW_TABS)] performAction:grey_tap()];
183 [[EarlGrey selectElementWithMatcher:
184 chrome_test_util::buttonWithAccessibilityLabelId(
185 IDS_IOS_TOOLS_MENU_NEW_INCOGNITO_TAB)]
186 performAction:grey_swipeFastInDirection(kGREYDirectionRight)];
187 [[EarlGrey selectElementWithMatcher:
188 chrome_test_util::buttonWithAccessibilityLabelId(
189 IDS_IOS_TOOLBAR_SHOW_TABS)] performAction:grey_tap()];
190 }
191 GREYAssertFalse(chrome_test_util::IsIncognitoMode(),
192 @"Switching to normal mode failed.");
193 }
194
195 // Check that the error page is visible.
196 void CheckErrorPageIsVisible() {
197 // The DNS error page is static HTML content, so it isn't part of the webview
198 // owned by the webstate.
199 [[EarlGrey selectElementWithMatcher:chrome_test_util::
200 webViewBelongingToWebController()]
201 assertWithMatcher:grey_nil()];
202 NSString* const kError =
203 l10n_util::GetNSString(IDS_ERRORPAGES_HEADING_NOT_AVAILABLE);
204 [[EarlGrey
205 selectElementWithMatcher:chrome_test_util::staticHtmlViewContainingText(
206 kError)] assertWithMatcher:grey_notNil()];
207 }
208
209 // Open the settings submenu. Assumes that settings menu is visible.
210 void OpenSettingsSubMenuUnsynced(int submenu) {
211 id<GREYMatcher> settings_button_matcher =
212 grey_text(l10n_util::GetNSString(submenu));
213 [[[EarlGrey selectElementWithMatcher:settings_button_matcher]
214 usingSearchAction:grey_swipeSlowInDirection(kGREYDirectionUp)
215 onElementWithMatcher:grey_accessibilityID(kSettingsCollectionViewId)]
216 performAction:grey_tap()];
217 }
218
219 // Open the settings menu. Wait for the settings menu to appear.
220 void OpenSettingsMenuUnsynced() {
221 id<GREYMatcher> tool_menu_matcher =
222 grey_accessibilityID(kToolbarToolsMenuButtonIdentifier);
223 WaitAndTap(tool_menu_matcher, @"Tool menu");
224
225 id<GREYMatcher> settings_button_matcher =
226 grey_accessibilityID(kToolsMenuSettingsId);
227
228 WaitAndTap(settings_button_matcher, @"Settings menu");
229 Wait(grey_accessibilityID(kSettingsCollectionViewId), @"Setting view");
230 }
231
232 // Select the tab with title |title| using UI (tab strip on iPad, stack view on
233 // iPhone).
234 void SelectTabUsingUI(NSString* title) {
235 if (IsCompact()) {
236 WaitAndTap(chrome_test_util::buttonWithAccessibilityLabelId(
237 IDS_IOS_TOOLBAR_SHOW_TABS),
238 @"Tab switcher");
239 }
240 WaitAndTap(grey_text(title),
241 [NSString stringWithFormat:@"tab with title %@", title]);
242 }
243 } // namespace
244
245 // Test for the TabUsageRecorder class.
246 @interface TabUsageRecorderTestCase : ChromeTestCase
247 @end
248
249 @implementation TabUsageRecorderTestCase
250
251 - (void)tearDown {
252 [[GREYConfiguration sharedInstance]
253 setValue:@(YES)
254 forConfigKey:kGREYConfigKeySynchronizationEnabled];
255 [super tearDown];
256 }
257
258 // Tests that the recorder actual recorde tab state.
259 - (void)testTabSwitchRecorder {
260 web::test::SetUpFileBasedHttpServer();
261 chrome_test_util::HistogramTester histogramTester;
262 ResetTabUsageRecorder();
263 FailureBlock failureBlock = ^(NSString* error) {
264 GREYFail(error);
265 };
266
267 // Open two tabs with urls.
268 OpenTwoTabs();
269 chrome_test_util::AssertMainTabCount(2);
270 // Switch between the two tabs. Both are currently in memory.
271 chrome_test_util::SelectTabAtIndexInCurrentMode(0);
272
273 // Verify that one in-memory tab switch has been recorded.
274 // histogramTester.ExpectTotalCount(kSelectedTabHistogramName, 1,
275 // failureBlock);
276 histogramTester.ExpectUniqueSample(
277 kSelectedTabHistogramName, TabUsageRecorder::IN_MEMORY, 1, failureBlock);
278
279 // Evict the tab.
280 OpenNewIncognitoTabUsingUIAndEvictMainTabs();
281 GREYAssertTrue(chrome_test_util::IsIncognitoMode(),
282 @"Failed to switch to incognito mode");
283
284 // Switch back to the normal tabs. Should be on tab one.
285 SwitchToNormalMode();
286 [[EarlGrey selectElementWithMatcher:chrome_test_util::webViewContainingText(
287 kURL1FirstWord)]
288 assertWithMatcher:grey_notNil()];
289
290 histogramTester.ExpectTotalCount(kSelectedTabHistogramName, 2, failureBlock);
291 histogramTester.ExpectBucketCount(kSelectedTabHistogramName,
292 TabUsageRecorder::EVICTED, 1, failureBlock);
293 }
294
295 // Verifies the UMA metric for page loads before a tab eviction by loading
296 // some tabs, forcing a tab eviction, then checking the histogram.
297 - (void)testPageLoadCountBeforeEvictedTab {
298 web::test::SetUpFileBasedHttpServer();
299 chrome_test_util::HistogramTester histogramTester;
300 ResetTabUsageRecorder();
301 const GURL url1 = web::test::HttpServer::MakeUrl(kTestUrl1);
302 FailureBlock failureBlock = ^(NSString* error) {
303 GREYFail(error);
304 };
305
306 // This test opens three tabs.
307 const int numberOfTabs = 3;
308 chrome_test_util::CloseAllTabsInCurrentMode();
309 // Open three tabs with http:// urls.
310 for (NSUInteger i = 0; i < numberOfTabs; i++) {
311 chrome_test_util::OpenNewTab();
312 [ChromeEarlGrey loadURL:url1];
313 [[EarlGrey selectElementWithMatcher:chrome_test_util::webViewContainingText(
314 kURL1FirstWord)]
315 assertWithMatcher:grey_notNil()];
316 }
317 chrome_test_util::AssertMainTabCount(numberOfTabs);
318
319 // Switch between the tabs. They are currently in memory.
320 chrome_test_util::SelectTabAtIndexInCurrentMode(0);
321
322 // Verify that no page-load count has been recorded.
323 histogramTester.ExpectTotalCount(kPageLoadsBeforeEvictedTabSelected, 0,
324 failureBlock);
325
326 // Reload each tab.
327 for (NSUInteger i = 0; i < numberOfTabs; i++) {
328 chrome_test_util::SelectTabAtIndexInCurrentMode(i);
329 // Clear the page so that we can check when pade reload is complete.
330 __block bool finished = false;
331 chrome_test_util::GetCurrentWebState()->ExecuteJavaScript(
332 base::UTF8ToUTF16(kClearPageScript),
333 base::BindBlock(^(const base::Value*) {
334 finished = true;
335 }));
336
337 GREYAssert(testing::WaitUntilConditionOrTimeout(1.0,
338 ^{
339 return finished;
340 }),
341 @"JavaScript to reload each tab did not finish");
342 [ChromeEarlGreyUI reload];
343 [[EarlGrey selectElementWithMatcher:chrome_test_util::webViewContainingText(
344 kURL1FirstWord)]
345 assertWithMatcher:grey_notNil()];
346 }
347
348 // Evict the tab. Create a dummy tab so that switching back to normal mode
349 // does not trigger a reload immediatly.
350 chrome_test_util::OpenNewTab();
351 OpenNewIncognitoTabUsingUIAndEvictMainTabs();
352 chrome_test_util::AssertIncognitoTabCount(1);
353
354 // Switch back to the normal tabs. Should be on tab one.
355 SwitchToNormalMode();
356 chrome_test_util::SelectTabAtIndexInCurrentMode(0);
357 [[EarlGrey selectElementWithMatcher:chrome_test_util::webViewContainingText(
358 kURL1FirstWord)]
359 assertWithMatcher:grey_notNil()];
360
361 // Verify that one page-load count has been recorded. It should contain two
362 // page loads for each tab created.
363 histogramTester.ExpectTotalCount(kPageLoadsBeforeEvictedTabSelected, 1,
364 failureBlock);
365
366 std::unique_ptr<base::HistogramSamples> samples =
367 histogramTester.GetHistogramSamplesSinceCreation(
368 kPageLoadsBeforeEvictedTabSelected);
369 int sampleSum = samples ? samples->sum() : 0;
370 GREYAssertEqual(
371 sampleSum, numberOfTabs * 2,
372 [NSString stringWithFormat:@"Expected page loads is %d, actual %d.",
373 numberOfTabs * 2, sampleSum]);
374 }
375
376 // Tests that tabs reloaded on cold start are reported as
377 // EVICTED_DUE_TO_COLD_START.
378 - (void)testColdLaunchReloadCount {
379 web::test::SetUpFileBasedHttpServer();
380 chrome_test_util::HistogramTester histogramTester;
381 ResetTabUsageRecorder();
382
383 // Open two tabs with urls.
384 OpenTwoTabs();
385 chrome_test_util::AssertMainTabCount(2);
386 // Set the normal tabs as 'cold start' tabs.
387 GREYAssertTrue(chrome_test_util::SetCurrentTabsToBeColdStartTabs(),
388 @"Fail to state tabs as cold start tabs");
389
390 // Open two incognito tabs with urls, clearing normal tabs from memory.
391 OpenNewIncognitoTabUsingUIAndEvictMainTabs();
392 OpenNewIncognitoTabUsingUIAndEvictMainTabs();
393 chrome_test_util::AssertIncognitoTabCount(2);
394
395 // Switch back to the normal tabs.
396 SwitchToNormalMode();
397 [[EarlGrey selectElementWithMatcher:chrome_test_util::webViewContainingText(
398 kURL2FirstWord)]
399 assertWithMatcher:grey_notNil()];
400
401 // Select the other one so it also reloads.
402 chrome_test_util::SelectTabAtIndexInCurrentMode(0);
403 [[EarlGrey selectElementWithMatcher:chrome_test_util::webViewContainingText(
404 kURL1FirstWord)]
405 assertWithMatcher:grey_notNil()];
406
407 FailureBlock failureBlock = ^(NSString* error) {
408 GREYFail(error);
409 };
410 // Make sure that one of the 2 tab loads (excluding the selected tab) is
411 // counted as a cold start eviction.
412 histogramTester.ExpectBucketCount(kSelectedTabHistogramName,
413 TabUsageRecorder::EVICTED_DUE_TO_COLD_START,
414 1, failureBlock);
415
416 histogramTester.ExpectBucketCount(
417 kSelectedTabHistogramName, TabUsageRecorder::IN_MEMORY, 0, failureBlock);
418 // Re-select the same tab and make sure it is not counted again as evicted.
419 chrome_test_util::SelectTabAtIndexInCurrentMode(1);
420 chrome_test_util::SelectTabAtIndexInCurrentMode(0);
421
422 [[EarlGrey selectElementWithMatcher:chrome_test_util::webViewContainingText(
423 kURL1FirstWord)]
424 assertWithMatcher:grey_notNil()];
425 histogramTester.ExpectBucketCount(kSelectedTabHistogramName,
426 TabUsageRecorder::EVICTED_DUE_TO_COLD_START,
427 1, failureBlock);
428
429 histogramTester.ExpectBucketCount(
430 kSelectedTabHistogramName, TabUsageRecorder::IN_MEMORY, 2, failureBlock);
431 }
432
433 // Tests that tabs reloads after backgrounding and eviction.
434 - (void)testBackgroundingReloadCount {
435 web::test::SetUpFileBasedHttpServer();
436 chrome_test_util::HistogramTester histogramTester;
437 ResetTabUsageRecorder();
438 FailureBlock failureBlock = ^(NSString* error) {
439 GREYFail(error);
440 };
441
442 // Open two tabs with urls.
443 OpenTwoTabs();
444 chrome_test_util::AssertMainTabCount(2);
445
446 // Simulate going into the background.
447 GREYAssertTrue(chrome_test_util::SimulateTabsBackgrounding(),
448 @"Fail to simulate tab backgrounding.");
449
450 // Open incognito and clear normal tabs from memory.
451 OpenNewIncognitoTabUsingUIAndEvictMainTabs();
452 GREYAssertTrue(chrome_test_util::IsIncognitoMode(),
453 @"Failed to switch to incognito mode");
454 histogramTester.ExpectTotalCount(kEvictedTabReloadTime, 0, failureBlock);
455
456 // Switch back to the normal tabs.
457 SwitchToNormalMode();
458 [[EarlGrey selectElementWithMatcher:chrome_test_util::webViewContainingText(
459 kURL2FirstWord)]
460 assertWithMatcher:grey_notNil()];
461
462 const GURL url1 = web::test::HttpServer::MakeUrl(kTestUrl1);
463 const GURL url2 = web::test::HttpServer::MakeUrl(kTestUrl2);
464 [[EarlGrey
465 selectElementWithMatcher:chrome_test_util::omniboxText(url2.GetContent())]
466 assertWithMatcher:grey_notNil()];
467 histogramTester.ExpectTotalCount(kEvictedTabReloadTime, 1, failureBlock);
468
469 chrome_test_util::SelectTabAtIndexInCurrentMode(0);
470 [[EarlGrey selectElementWithMatcher:chrome_test_util::webViewContainingText(
471 kURL1FirstWord)]
472 assertWithMatcher:grey_notNil()];
473 [[EarlGrey
474 selectElementWithMatcher:chrome_test_util::omniboxText(url1.GetContent())]
475 assertWithMatcher:grey_notNil()];
476 histogramTester.ExpectTotalCount(kEvictedTabReloadTime, 2, failureBlock);
477 }
478
479 // Verify correct recording of metrics when the reloading of an evicted tab
480 // succeeds.
481 - (void)testEvictedTabReloadSuccess {
482 web::test::SetUpFileBasedHttpServer();
483 chrome_test_util::HistogramTester histogramTester;
484 FailureBlock failureBlock = ^(NSString* error) {
485 GREYFail(error);
486 };
487
488 GURL URL = web::test::HttpServer::MakeUrl(kTestUrl1);
489 NewMainTabWithURL(URL, kURL1FirstWord);
490 OpenNewIncognitoTabUsingUIAndEvictMainTabs();
491 SwitchToNormalMode();
492 [[EarlGrey selectElementWithMatcher:chrome_test_util::webViewContainingText(
493 kURL1FirstWord)]
494 assertWithMatcher:grey_notNil()];
495
496 histogramTester.ExpectUniqueSample(kEvictedTabReloadSuccessRate,
497 TabUsageRecorder::LOAD_SUCCESS, 1,
498 failureBlock);
499 histogramTester.ExpectUniqueSample(kDidUserWaitForEvictedTabReload,
500 TabUsageRecorder::USER_WAITED, 1,
501 failureBlock);
502 histogramTester.ExpectTotalCount(kEvictedTabReloadTime, 1, failureBlock);
503 }
504
505 // Verify correct recording of metrics when the reloading of an evicted tab
506 // fails.
507 - (void)testEvictedTabReloadFailure {
508 web::test::SetUpFileBasedHttpServer();
509 chrome_test_util::HistogramTester histogramTester;
510 FailureBlock failureBlock = ^(NSString* error) {
511 GREYFail(error);
512 };
513
514 // This URL is purposely invalid so it triggers a navigation error.
515 GURL invalidURL(kTestUrl1);
516
517 chrome_test_util::OpenNewTab();
518 [ChromeEarlGrey loadURL:invalidURL];
519 CheckErrorPageIsVisible();
520 OpenNewIncognitoTabUsingUIAndEvictMainTabs();
521
522 SwitchToNormalMode();
523 CheckErrorPageIsVisible();
524
525 histogramTester.ExpectUniqueSample(kEvictedTabReloadSuccessRate,
526 TabUsageRecorder::LOAD_FAILURE, 1,
527 failureBlock);
528 histogramTester.ExpectUniqueSample(kDidUserWaitForEvictedTabReload,
529 TabUsageRecorder::USER_WAITED, 1,
530 failureBlock);
531 histogramTester.ExpectTotalCount(kEvictedTabReloadTime, 0, failureBlock);
532 }
533
534 // Test that USER_DID_NOT_WAIT is reported if the user does not wait for the
535 // reload to be complete after eviction.
536 - (void)testEvictedTabSlowReload {
537 std::map<GURL, std::string> responses;
538 const GURL slowURL = web::test::HttpServer::MakeUrl("http://slow");
539 responses[slowURL] = "Slow Page";
540
541 web::test::SetUpHttpServer(base::MakeUnique<web::DelayedResponseProvider>(
542 base::MakeUnique<HtmlResponseProvider>(responses), kSlowURLDelay));
543
544 chrome_test_util::HistogramTester histogramTester;
545 FailureBlock failureBlock = ^(NSString* error) {
546 GREYFail(error);
547 };
548
549 // A blank tab needed to switch to it after reloading.
550 chrome_test_util::OpenNewTab();
551 chrome_test_util::OpenNewTab();
552 chrome_test_util::LoadUrl(slowURL);
553 OpenNewIncognitoTabUsingUIAndEvictMainTabs();
554
555 web::test::SetUpHttpServer(base::MakeUnique<web::DelayedResponseProvider>(
556 base::MakeUnique<HtmlResponseProvider>(responses), kSlowURLDelay));
557
558 SwitchToNormalMode();
559
560 GREYAssert(
561 [[GREYCondition conditionWithName:@"Wait for tab to restart loading."
562 block:^BOOL() {
563 return chrome_test_util::IsLoading();
564 }] waitWithTimeout:kWaitElementTimeout],
565 @"Tab did not start loading.");
566
567 // This method is not synced on EarlGrey.
568 chrome_test_util::SelectTabAtIndexInCurrentMode(0);
569
570 // Do not test the kEvictedTabReloadSuccessRate, as the timing of the two
571 // page loads cannot be guaranteed. The test would be flaky.
572 histogramTester.ExpectBucketCount(kDidUserWaitForEvictedTabReload,
573 TabUsageRecorder::USER_DID_NOT_WAIT, 1,
574 failureBlock);
575 }
576
577 // Test that the USER_DID_NOT_WAIT metric is logged when the user opens an NTP
578 // while the evicted tab is still reloading.
579 - (void)testEvictedTabReloadSwitchToNTP {
580 std::map<GURL, std::string> responses;
581 const GURL slowURL = web::test::HttpServer::MakeUrl("http://slow");
582 responses[slowURL] = "Slow Page";
583
584 web::test::SetUpHttpServer(base::MakeUnique<HtmlResponseProvider>(responses));
585
586 chrome_test_util::HistogramTester histogramTester;
587 FailureBlock failureBlock = ^(NSString* error) {
588 GREYFail(error);
589 };
590
591 NewMainTabWithURL(slowURL, "Slow");
592
593 OpenNewIncognitoTabUsingUIAndEvictMainTabs();
594 web::test::SetUpHttpServer(base::MakeUnique<web::DelayedResponseProvider>(
595 base::MakeUnique<HtmlResponseProvider>(responses), kSlowURLDelay));
596
597 SwitchToNormalMode();
598
599 // TODO(crbug.com/640977): EarlGrey synchronize on some animations when a
600 // page is loading. Need to handle synchronization manually for this test.
601 [[GREYConfiguration sharedInstance]
602 setValue:@(NO)
603 forConfigKey:kGREYConfigKeySynchronizationEnabled];
604 OpenNewMainTabUsingUIUnsynced();
605 [[GREYConfiguration sharedInstance]
606 setValue:@(YES)
607 forConfigKey:kGREYConfigKeySynchronizationEnabled];
608 histogramTester.ExpectBucketCount(kDidUserWaitForEvictedTabReload,
609 TabUsageRecorder::USER_DID_NOT_WAIT, 1,
610 failureBlock);
611 }
612
613 // Test that the USER_DID_NOT_WAIT metric is not logged when the user opens
614 // and closes the settings UI while the evicted tab is still reloading.
615 - (void)testEvictedTabReloadSettingsAndBack {
616 std::map<GURL, std::string> responses;
617 const GURL slowURL = web::test::HttpServer::MakeUrl("http://slow");
618 responses[slowURL] = "Slow Page";
619
620 web::test::SetUpHttpServer(base::MakeUnique<web::DelayedResponseProvider>(
621 base::MakeUnique<HtmlResponseProvider>(responses), kSlowURLDelay));
622
623 chrome_test_util::HistogramTester histogramTester;
624 FailureBlock failureBlock = ^(NSString* error) {
625 GREYFail(error);
626 };
627
628 NewMainTabWithURL(slowURL, responses[slowURL]);
629
630 OpenNewIncognitoTabUsingUIAndEvictMainTabs();
631
632 SwitchToNormalMode();
633 // TODO(crbug.com/640977): EarlGrey synchronize on some animations when a
634 // page is loading. Need to handle synchronization manually for this test.
635 [[GREYConfiguration sharedInstance]
636 setValue:@(NO)
637 forConfigKey:kGREYConfigKeySynchronizationEnabled];
638 OpenSettingsMenuUnsynced();
639 OpenSettingsSubMenuUnsynced(IDS_OPTIONS_ADVANCED_SECTION_TITLE_PRIVACY);
640 Wait(grey_accessibilityID(kPrivacyCollectionViewId),
641 @"Privacy settings view.");
642
643 WaitAndTap(grey_accessibilityLabel(
644 l10n_util::GetNSString(IDS_IOS_NAVIGATION_BAR_DONE_BUTTON)),
645 @"Close settings");
646 [[GREYUIThreadExecutor sharedInstance] drainUntilIdle];
647 [[EarlGrey selectElementWithMatcher:chrome_test_util::webViewContainingText(
648 responses[slowURL])]
649 assertWithMatcher:grey_notNil()];
650
651 [[GREYConfiguration sharedInstance]
652 setValue:@(YES)
653 forConfigKey:kGREYConfigKeySynchronizationEnabled];
654
655 histogramTester.ExpectBucketCount(kDidUserWaitForEvictedTabReload,
656 TabUsageRecorder::USER_DID_NOT_WAIT, 0,
657 failureBlock);
658 histogramTester.ExpectBucketCount(kDidUserWaitForEvictedTabReload,
659 TabUsageRecorder::USER_WAITED, 1,
660 failureBlock);
661 }
662
663 // Tests that leaving Chrome while an evicted tab is reloading triggers the
664 // recording of the USER_LEFT_CHROME metric.
665 - (void)testEvictedTabReloadBackgrounded {
666 std::map<GURL, std::string> responses;
667 const GURL slowURL = web::test::HttpServer::MakeUrl("http://slow");
668 responses[slowURL] = "Slow Page";
669
670 web::test::SetUpHttpServer(base::MakeUnique<HtmlResponseProvider>(responses));
671
672 chrome_test_util::HistogramTester histogramTester;
673 chrome_test_util::OpenNewTab();
674 chrome_test_util::LoadUrl(slowURL);
675
676 OpenNewIncognitoTabUsingUIAndEvictMainTabs();
677
678 web::test::SetUpHttpServer(base::MakeUnique<web::DelayedResponseProvider>(
679 base::MakeUnique<HtmlResponseProvider>(responses), kSlowURLDelay));
680 SwitchToNormalMode();
681
682 // TODO(crbug.com/640977): EarlGrey synchronize on some animations when a
683 // page is loading. Need to handle synchronization manually for this test.
684 [[GREYConfiguration sharedInstance]
685 setValue:@(NO)
686 forConfigKey:kGREYConfigKeySynchronizationEnabled];
687 id<GREYMatcher> toolMenuMatcher =
688 grey_accessibilityID(kToolbarToolsMenuButtonIdentifier);
689 Wait(toolMenuMatcher, @"Tool Menu");
690
691 GREYAssertTrue(chrome_test_util::SimulateTabsBackgrounding(),
692 @"Failed to simulate tab backgrounding.");
693 [[GREYConfiguration sharedInstance]
694 setValue:@(YES)
695 forConfigKey:kGREYConfigKeySynchronizationEnabled];
696
697 FailureBlock failureBlock = ^(NSString* error) {
698 GREYFail(error);
699 };
700 histogramTester.ExpectBucketCount(kDidUserWaitForEvictedTabReload,
701 TabUsageRecorder::USER_LEFT_CHROME, 1,
702 failureBlock);
703 }
704
705 // Tests that backgrounding a tab that was not evicted while it is loading does
706 // not record the USER_LEFT_CHROME metric.
707 - (void)testLiveTabReloadBackgrounded {
708 std::map<GURL, std::string> responses;
709 const GURL slowURL = web::test::HttpServer::MakeUrl("http://slow");
710 responses[slowURL] = "Slow Page";
711
712 web::test::SetUpHttpServer(base::MakeUnique<web::DelayedResponseProvider>(
713 base::MakeUnique<HtmlResponseProvider>(responses), kSlowURLDelay));
714
715 chrome_test_util::HistogramTester histogramTester;
716
717 // We need two tabs to be able to switch.
718 chrome_test_util::OpenNewTab();
719 [[GREYConfiguration sharedInstance]
720 setValue:@(NO)
721 forConfigKey:kGREYConfigKeySynchronizationEnabled];
722 chrome_test_util::LoadUrl(slowURL);
723
724 // Ensure loading starts but is not finished.
725 base::test::ios::SpinRunLoopWithMaxDelay(base::TimeDelta::FromSeconds(1));
726 chrome_test_util::SelectTabAtIndexInCurrentMode(0);
727 [[GREYConfiguration sharedInstance]
728 setValue:@(YES)
729 forConfigKey:kGREYConfigKeySynchronizationEnabled];
730
731 FailureBlock failureBlock = ^(NSString* error) {
732 GREYFail(error);
733 };
734 histogramTester.ExpectBucketCount(kDidUserWaitForEvictedTabReload,
735 TabUsageRecorder::USER_LEFT_CHROME, 0,
736 failureBlock);
737 }
738
739 // Tests that redirecting pages are not reloaded after eviction.
740 - (void)testPageRedirect {
741 GURL redirectURL = web::test::HttpServer::MakeUrl(
742 "http://ios/testing/data/http_server_files/redirect_refresh.html");
743 GURL destinationURL = web::test::HttpServer::MakeUrl(
744 "http://ios/testing/data/http_server_files/destination.html");
745 web::test::SetUpFileBasedHttpServer();
746 chrome_test_util::HistogramTester histogramTester;
747 ResetTabUsageRecorder();
748
749 NewMainTabWithURL(redirectURL, "arrived");
750
751 [[EarlGrey selectElementWithMatcher:chrome_test_util::omniboxText(
752 destinationURL.GetContent())]
753 assertWithMatcher:grey_notNil()];
754
755 NSUInteger tabIndex = chrome_test_util::GetMainTabCount() - 1;
756 chrome_test_util::OpenNewTab();
757 OpenNewIncognitoTabUsingUIAndEvictMainTabs();
758 SwitchToNormalMode();
759 chrome_test_util::SelectTabAtIndexInCurrentMode(tabIndex);
760 [[EarlGrey selectElementWithMatcher:chrome_test_util::webViewContainingText(
761 "arrived")]
762 assertWithMatcher:grey_notNil()];
763
764 FailureBlock failureBlock = ^(NSString* error) {
765 GREYFail(error);
766 };
767 // Verify that one page-load count has been recorded. It should contain a
768 // sum of 1 - one sample with 1 page load.
769 histogramTester.ExpectTotalCount(kPageLoadsBeforeEvictedTabSelected, 1,
770 failureBlock);
771
772 std::unique_ptr<base::HistogramSamples> samples =
773 histogramTester.GetHistogramSamplesSinceCreation(
774 kPageLoadsBeforeEvictedTabSelected);
775 int sampleSum = samples->sum();
776 GREYAssertEqual(
777 sampleSum, 1,
778 [NSString stringWithFormat:@"Expected page loads is %d, actual is %d.", 1,
779 sampleSum]);
780 }
781
782 // Tests that navigations are correctly reported in
783 // Tab.PageLoadsSinceLastSwitchToEvictedTab histogram.
784 - (void)testLinkClickNavigation {
785 // Create map of canned responses and set up the test HTML server.
786 std::map<GURL, std::string> responses;
787 const GURL initialURL =
788 web::test::HttpServer::MakeUrl("http://scenarioTestLinkClickNavigation");
789 const GURL destinationURL =
790 web::test::HttpServer::MakeUrl("http://destination");
791 responses[initialURL] = base::StringPrintf(
792 "<body><a style='margin-left:50px' href='%s' id='link'>link</a></body>",
793 destinationURL.spec().c_str());
794 responses[destinationURL] = "Whee!";
795 web::test::SetUpHttpServer(base::MakeUnique<HtmlResponseProvider>(responses));
796 chrome_test_util::HistogramTester histogramTester;
797 ResetTabUsageRecorder();
798
799 // Open a tab with a link to click.
800 NewMainTabWithURL(initialURL, "link");
801 // Click the link.
802 chrome_test_util::TapWebViewElementWithId("link");
803
804 [[EarlGrey
805 selectElementWithMatcher:chrome_test_util::webViewContainingText("Whee")]
806 assertWithMatcher:grey_notNil()];
807
808 NSUInteger tabIndex = chrome_test_util::GetMainTabCount() - 1;
809 chrome_test_util::OpenNewTab();
810 OpenNewIncognitoTabUsingUIAndEvictMainTabs();
811 SwitchToNormalMode();
812 chrome_test_util::SelectTabAtIndexInCurrentMode(tabIndex);
813 [[EarlGrey
814 selectElementWithMatcher:chrome_test_util::webViewContainingText("Whee")]
815 assertWithMatcher:grey_notNil()];
816
817 // Verify that the page-load count has been recorded. It should contain a
818 // sum of 2 - one sample with 2 page loads.
819 std::unique_ptr<base::HistogramSamples> samples =
820 histogramTester.GetHistogramSamplesSinceCreation(
821 kPageLoadsBeforeEvictedTabSelected);
822 int sampleSum = samples->sum();
823 GREYAssertEqual(
824 sampleSum, 2,
825 [NSString stringWithFormat:@"Expected page loads is %d, actual %d.", 2,
826 sampleSum]);
827
828 FailureBlock failureBlock = ^(NSString* error) {
829 GREYFail(error);
830 };
831 // Verify that only one evicted tab was selected. This is to make sure the
832 // link click did not generate an evicted-tab-reload count.
833 histogramTester.ExpectBucketCount(kSelectedTabHistogramName,
834 TabUsageRecorder::EVICTED, 1, failureBlock);
835 }
836
837 // Tests that opening links in a new tab will not evict the source tab.
838 - (void)testOpenLinkInNewTab {
839 // Create map of canned responses and set up the test HTML server.
840 std::map<GURL, std::string> responses;
841 const GURL initialURL =
842 web::test::HttpServer::MakeUrl("http://scenarioTestOpenLinkInNewTab");
843 const GURL destinationURL =
844 web::test::HttpServer::MakeUrl("http://destination");
845 // Make the link that cover the whole page so that long pressing the web view
846 // will trigger the link context menu.
847 responses[initialURL] = base::StringPrintf(
848 "<body style='width:auto; height:auto;'><a href='%s' "
849 "id='link'><div style='width:100%%; "
850 "height:100%%;'>link</div></a></body>",
851 destinationURL.spec().c_str());
852 responses[destinationURL] = "Whee!";
853 web::test::SetUpHttpServer(base::MakeUnique<HtmlResponseProvider>(responses));
854 chrome_test_util::HistogramTester histogramTester;
855 ResetTabUsageRecorder();
856
857 // Open a tab with a link to click.
858 NewMainTabWithURL(initialURL, "link");
859
860 int numberOfTabs = chrome_test_util::GetMainTabCount();
861 [[EarlGrey
862 selectElementWithMatcher:chrome_test_util::webViewContainingText("link")]
863 performAction:grey_longPress()];
864
865 [[EarlGrey
866 selectElementWithMatcher:grey_text(l10n_util::GetNSString(
867 IDS_IOS_CONTENT_CONTEXT_OPENLINKNEWTAB))]
868 performAction:grey_tap()];
869 chrome_test_util::AssertMainTabCount(numberOfTabs + 1);
870
871 SelectTabUsingUI(base::SysUTF8ToNSString(destinationURL.GetContent()));
872
873 [[GREYUIThreadExecutor sharedInstance] drainUntilIdle];
874 [[EarlGrey
875 selectElementWithMatcher:chrome_test_util::webViewContainingText("Whee")]
876 assertWithMatcher:grey_notNil()];
877
878 FailureBlock failureBlock = ^(NSString* error) {
879 GREYFail(error);
880 };
881 histogramTester.ExpectTotalCount(kSelectedTabHistogramName, 1, failureBlock);
882 histogramTester.ExpectBucketCount(
883 kSelectedTabHistogramName, TabUsageRecorder::IN_MEMORY, 1, failureBlock);
884 }
885
886 // Tests that opening tabs from external app will not cause tab eviction.
887 - (void)testOpenFromApp {
888 web::test::SetUpFileBasedHttpServer();
889 chrome_test_util::HistogramTester histogramTester;
890 ResetTabUsageRecorder();
891
892 chrome_test_util::OpenNewTab();
893 GURL url(kTestUrl1);
894
895 chrome_test_util::OpenChromeFromExternalApp(url);
896
897 // Add a delay to ensure the tab has fully opened. Because the check below
898 // is for zero metrics recorded, it adds no flakiness. However, this pause
899 // makes the step more likely to fail in failure cases. I.e. without it, this
900 // test would sometimes pass even when it should fail.
901 base::test::ios::SpinRunLoopWithMaxDelay(
902 base::TimeDelta::FromMilliseconds(500));
903
904 FailureBlock failureBlock = ^(NSString* error) {
905 GREYFail(error);
906 };
907 // Verify that zero Tab.StatusWhenSwitchedBackToForeground metrics were
908 // recorded. Tabs created at the time the user switches to them should not
909 // be counted in this metric.
910 histogramTester.ExpectTotalCount(kSelectedTabHistogramName, 0, failureBlock);
911 }
912
913 // Verify that evicted tabs that are deleted are removed from the evicted tabs
914 // map.
915 - (void)testTabDeletion {
916 web::test::SetUpFileBasedHttpServer();
917 chrome_test_util::HistogramTester histogramTester;
918 ResetTabUsageRecorder();
919 // Add an autorelease pool to delete the closed tabs before the end of the
920 // test.
921 @autoreleasepool {
922 // Open two tabs with urls.
923 OpenTwoTabs();
924 // Set the normal tabs as 'cold start' tabs.
925 chrome_test_util::SetCurrentTabsToBeColdStartTabs();
926 // One more tab.
927 const GURL url1 = web::test::HttpServer::MakeUrl(kTestUrl1);
928 NewMainTabWithURL(url1, kURL1FirstWord);
929
930 GREYAssertEqual(chrome_test_util::GetMainTabCount(), 3,
931 @"Check number of normal tabs");
932 // The cold start tab which was not active will still be evicted.
933 GREYAssertEqual(chrome_test_util::GetEvictedMainTabCount(), 1,
934 @"Check number of evicted tabs");
935
936 // Close two of the three open tabs without selecting them first.
937 // This should delete the tab objects, even though they're still being
938 // tracked
939 // by the tab usage recorder in its |evicted_tabs_| map.
940 CloseTabAtIndexAndSync(1);
941
942 GREYAssertEqual(chrome_test_util::GetMainTabCount(), 2,
943 @"Check number of normal tabs");
944 CloseTabAtIndexAndSync(0);
945 GREYAssertEqual(chrome_test_util::GetMainTabCount(), 1,
946 @"Check number of normal tabs");
947 [[GREYUIThreadExecutor sharedInstance] drainUntilIdle];
948 }
949 // The deleted tabs are purged during foregrounding and backgrounding.
950 chrome_test_util::SimulateTabsBackgrounding();
951 // Make sure |evicted_tabs_| purged the deleted tabs.
952 int evicted = chrome_test_util::GetEvictedMainTabCount();
953 GREYAssertEqual(evicted, 0, @"Check number of evicted tabs");
954 }
955
956 @end
OLDNEW
« no previous file with comments | « ios/chrome/browser/metrics/tab_usage_recorder_delegate.h ('k') | ios/chrome/browser/metrics/tab_usage_recorder_unittest.mm » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698