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

Unified 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 side-by-side diff with in-line comments
Download patch
Index: ios/chrome/browser/metrics/tab_usage_recorder_egtest.mm
diff --git a/ios/chrome/browser/metrics/tab_usage_recorder_egtest.mm b/ios/chrome/browser/metrics/tab_usage_recorder_egtest.mm
new file mode 100644
index 0000000000000000000000000000000000000000..969d354269b60aaabfad9971a9fe0bc1b32e6eb5
--- /dev/null
+++ b/ios/chrome/browser/metrics/tab_usage_recorder_egtest.mm
@@ -0,0 +1,956 @@
+// Copyright 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.
+
+#import <EarlGrey/EarlGrey.h>
+#import <XCTest/XCTest.h>
+
+#include "base/mac/bind_objc_block.h"
+#include "base/memory/ptr_util.h"
+#include "base/strings/stringprintf.h"
+#include "base/strings/sys_string_conversions.h"
+#include "base/strings/utf_string_conversions.h"
+#import "base/test/ios/wait_util.h"
+#include "components/strings/grit/components_strings.h"
+#include "ios/chrome/browser/experimental_flags.h"
+#import "ios/chrome/browser/metrics/tab_usage_recorder.h"
+#import "ios/chrome/browser/ui/settings/privacy_collection_view_controller.h"
+#import "ios/chrome/browser/ui/settings/settings_collection_view_controller.h"
+#import "ios/chrome/browser/ui/toolbar/toolbar_controller.h"
+#import "ios/chrome/browser/ui/tools_menu/tools_menu_view_controller.h"
+#include "ios/chrome/browser/ui/ui_util.h"
+#import "ios/chrome/browser/ui/uikit_ui_util.h"
+#include "ios/chrome/grit/ios_strings.h"
+#import "ios/chrome/test/app/chrome_test_util.h"
+#import "ios/chrome/test/app/histogram_test_util.h"
+#include "ios/chrome/test/app/navigation_test_util.h"
+#import "ios/chrome/test/app/tab_test_util.h"
+#include "ios/chrome/test/app/web_view_interaction_test_util.h"
+#import "ios/chrome/test/earl_grey/chrome_assertions.h"
+#import "ios/chrome/test/earl_grey/chrome_earl_grey.h"
+#import "ios/chrome/test/earl_grey/chrome_earl_grey_ui.h"
+#import "ios/chrome/test/earl_grey/chrome_matchers.h"
+#import "ios/chrome/test/earl_grey/chrome_test_case.h"
+#import "ios/testing/wait_util.h"
+#import "ios/web/public/test/http_server.h"
+#import "ios/web/public/test/http_server_util.h"
+#include "ios/web/public/test/response_providers/delayed_response_provider.h"
+#include "ios/web/public/test/response_providers/html_response_provider.h"
+#include "ui/base/l10n/l10n_util.h"
+#include "ui/base/l10n/l10n_util_mac.h"
+
+namespace {
+
+const char kTestUrl1[] =
+ "http://ios/testing/data/http_server_files/memory_usage.html";
+const char kURL1FirstWord[] = "Page";
+const char kTestUrl2[] =
+ "http://ios/testing/data/http_server_files/fullscreen.html";
+const char kURL2FirstWord[] = "Rugby";
+const char kClearPageScript[] = "document.body.innerHTML='';";
+
+// The delay to use to serve slow URLs.
+const CGFloat kSlowURLDelay = 3;
+
+// The delay to wait for an element to appear before tapping on it.
+const CGFloat kWaitElementTimeout = 3;
+
+void ResetTabUsageRecorder() {
+ GREYAssertTrue(chrome_test_util::ResetTabUsageRecorder(),
+ @"Fail to reset the TabUsageRecorder");
+}
+
+// Wait until |matcher| is accessible (not nil).
+void Wait(id<GREYMatcher> matcher, NSString* name) {
+ ConditionBlock condition = ^{
+ NSError* error = nil;
+ [[EarlGrey selectElementWithMatcher:matcher] assertWithMatcher:grey_notNil()
+ error:&error];
+ return error == nil;
+ };
+ GREYAssert(
+ testing::WaitUntilConditionOrTimeout(kWaitElementTimeout, condition),
+ [NSString stringWithFormat:@"Waiting for matcher %@ failed.", name]);
+}
+
+// Wait until |matcher| is accessible (not nil) and tap on it.
+void WaitAndTap(id<GREYMatcher> matcher, NSString* name) {
+ Wait(matcher, name);
+ [[EarlGrey selectElementWithMatcher:matcher] performAction:grey_tap()];
+}
+
+// Creates a new main tab and load |url|. Wait until |word| is visible on the
+// page.
+void NewMainTabWithURL(const GURL& url, const std::string& word) {
+ int number_of_tabs = chrome_test_util::GetMainTabCount();
+ chrome_test_util::OpenNewTab();
+ [ChromeEarlGrey loadURL:url];
+ [[EarlGrey
+ selectElementWithMatcher:chrome_test_util::webViewContainingText(word)]
+ assertWithMatcher:grey_notNil()];
+ chrome_test_util::AssertMainTabCount(number_of_tabs + 1);
+}
+
+// Opens 2 new tabs with different URLs.
+void OpenTwoTabs() {
+ chrome_test_util::CloseAllTabsInCurrentMode();
+
+ const GURL url1 = web::test::HttpServer::MakeUrl(kTestUrl1);
+ const GURL url2 = web::test::HttpServer::MakeUrl(kTestUrl2);
+ NewMainTabWithURL(url1, kURL1FirstWord);
+ NewMainTabWithURL(url2, kURL2FirstWord);
+}
+
+// Opens a new main tab using the UI. This method is using ad-hoc
+// synchronization.
+void OpenNewMainTabUsingUIUnsynced() {
+ int nb_main_tab = chrome_test_util::GetMainTabCount();
+ id<GREYMatcher> tool_menu_matcher =
+ grey_accessibilityID(kToolbarToolsMenuButtonIdentifier);
+ WaitAndTap(tool_menu_matcher, @"Tool menu");
+ id<GREYMatcher> new_main_tab_button_matcher =
+ grey_accessibilityID(kToolsMenuNewTabId);
+ WaitAndTap(new_main_tab_button_matcher, @"New tab button");
+
+ chrome_test_util::AssertMainTabCount(nb_main_tab + 1);
+}
+
+// Opens a new incognito tab using the UI and evicts any main tab model tabs.
+void OpenNewIncognitoTabUsingUIAndEvictMainTabs() {
+ int nb_incognito_tab = chrome_test_util::GetIncognitoTabCount();
+ [ChromeEarlGreyUI openToolsMenu];
+ id<GREYMatcher> new_incognito_tab_button_matcher =
+ grey_accessibilityID(kToolsMenuNewIncognitoTabId);
+ [[EarlGrey selectElementWithMatcher:new_incognito_tab_button_matcher]
+ performAction:grey_tap()];
+ chrome_test_util::AssertIncognitoTabCount(nb_incognito_tab + 1);
+
+ chrome_test_util::EvictOtherTabModelTabs();
+}
+
+// Closes a tab in the current tab model. Synchronize on tab number afterwards.
+void CloseTabAtIndexAndSync(NSUInteger i) {
+ NSUInteger nb_main_tab = chrome_test_util::GetMainTabCount();
+ chrome_test_util::CloseTabAtIndex(i);
+ ConditionBlock condition = ^{
+ return chrome_test_util::GetMainTabCount() == (nb_main_tab - 1);
+ };
+ GREYAssert(
+ testing::WaitUntilConditionOrTimeout(kWaitElementTimeout, condition),
+ @"Waiting for tab to close");
+}
+
+// Closes the tabs switcher.
+void CloseTabSwitcher() {
+ id<GREYMatcher> matcher = chrome_test_util::buttonWithAccessibilityLabelId(
+ IDS_IOS_TAB_STRIP_LEAVE_TAB_SWITCHER);
+ [[EarlGrey selectElementWithMatcher:matcher] performAction:grey_tap()];
+}
+
+// Swithches to normal mode using swith button (iPad) or stack view (iPhone).
+// Assumes current mode is Incognito.
+void SwitchToNormalMode() {
+ GREYAssertTrue(chrome_test_util::IsIncognitoMode(),
+ @"Switching to normal mode is only allowed from Incognito.");
+ if (IsIPadIdiom()) {
+ if (experimental_flags::IsTabSwitcherEnabled()) {
+ // Enter the tab switcher.
+ id<GREYMatcher> tabSwitcherEnterButton =
+ grey_accessibilityLabel(l10n_util::GetNSStringWithFixup(
+ IDS_IOS_TAB_STRIP_ENTER_TAB_SWITCHER));
+ [[EarlGrey selectElementWithMatcher:tabSwitcherEnterButton]
+ performAction:grey_tap()];
+
+ // Select the non incognito panel.
+ id<GREYMatcher> tabSwitcherHeaderPanelButton =
+ grey_accessibilityLabel(l10n_util::GetNSStringWithFixup(
+ IDS_IOS_TAB_SWITCHER_HEADER_NON_INCOGNITO_TABS));
+ [[EarlGrey selectElementWithMatcher:tabSwitcherHeaderPanelButton]
+ performAction:grey_tap()];
+
+ // Leave the tab switcher.
+ CloseTabSwitcher();
+ } else {
+ [[EarlGrey selectElementWithMatcher:
+ chrome_test_util::buttonWithAccessibilityLabelId(
+ IDS_IOS_SWITCH_BROWSER_MODE_LEAVE_INCOGNITO)]
+ performAction:grey_tap()];
+ }
+ } else {
+ [[EarlGrey selectElementWithMatcher:
+ chrome_test_util::buttonWithAccessibilityLabelId(
+ IDS_IOS_TOOLBAR_SHOW_TABS)] performAction:grey_tap()];
+ [[EarlGrey selectElementWithMatcher:
+ chrome_test_util::buttonWithAccessibilityLabelId(
+ IDS_IOS_TOOLS_MENU_NEW_INCOGNITO_TAB)]
+ performAction:grey_swipeFastInDirection(kGREYDirectionRight)];
+ [[EarlGrey selectElementWithMatcher:
+ chrome_test_util::buttonWithAccessibilityLabelId(
+ IDS_IOS_TOOLBAR_SHOW_TABS)] performAction:grey_tap()];
+ }
+ GREYAssertFalse(chrome_test_util::IsIncognitoMode(),
+ @"Switching to normal mode failed.");
+}
+
+// Check that the error page is visible.
+void CheckErrorPageIsVisible() {
+ // The DNS error page is static HTML content, so it isn't part of the webview
+ // owned by the webstate.
+ [[EarlGrey selectElementWithMatcher:chrome_test_util::
+ webViewBelongingToWebController()]
+ assertWithMatcher:grey_nil()];
+ NSString* const kError =
+ l10n_util::GetNSString(IDS_ERRORPAGES_HEADING_NOT_AVAILABLE);
+ [[EarlGrey
+ selectElementWithMatcher:chrome_test_util::staticHtmlViewContainingText(
+ kError)] assertWithMatcher:grey_notNil()];
+}
+
+// Open the settings submenu. Assumes that settings menu is visible.
+void OpenSettingsSubMenuUnsynced(int submenu) {
+ id<GREYMatcher> settings_button_matcher =
+ grey_text(l10n_util::GetNSString(submenu));
+ [[[EarlGrey selectElementWithMatcher:settings_button_matcher]
+ usingSearchAction:grey_swipeSlowInDirection(kGREYDirectionUp)
+ onElementWithMatcher:grey_accessibilityID(kSettingsCollectionViewId)]
+ performAction:grey_tap()];
+}
+
+// Open the settings menu. Wait for the settings menu to appear.
+void OpenSettingsMenuUnsynced() {
+ id<GREYMatcher> tool_menu_matcher =
+ grey_accessibilityID(kToolbarToolsMenuButtonIdentifier);
+ WaitAndTap(tool_menu_matcher, @"Tool menu");
+
+ id<GREYMatcher> settings_button_matcher =
+ grey_accessibilityID(kToolsMenuSettingsId);
+
+ WaitAndTap(settings_button_matcher, @"Settings menu");
+ Wait(grey_accessibilityID(kSettingsCollectionViewId), @"Setting view");
+}
+
+// Select the tab with title |title| using UI (tab strip on iPad, stack view on
+// iPhone).
+void SelectTabUsingUI(NSString* title) {
+ if (IsCompact()) {
+ WaitAndTap(chrome_test_util::buttonWithAccessibilityLabelId(
+ IDS_IOS_TOOLBAR_SHOW_TABS),
+ @"Tab switcher");
+ }
+ WaitAndTap(grey_text(title),
+ [NSString stringWithFormat:@"tab with title %@", title]);
+}
+} // namespace
+
+// Test for the TabUsageRecorder class.
+@interface TabUsageRecorderTestCase : ChromeTestCase
+@end
+
+@implementation TabUsageRecorderTestCase
+
+- (void)tearDown {
+ [[GREYConfiguration sharedInstance]
+ setValue:@(YES)
+ forConfigKey:kGREYConfigKeySynchronizationEnabled];
+ [super tearDown];
+}
+
+// Tests that the recorder actual recorde tab state.
+- (void)testTabSwitchRecorder {
+ web::test::SetUpFileBasedHttpServer();
+ chrome_test_util::HistogramTester histogramTester;
+ ResetTabUsageRecorder();
+ FailureBlock failureBlock = ^(NSString* error) {
+ GREYFail(error);
+ };
+
+ // Open two tabs with urls.
+ OpenTwoTabs();
+ chrome_test_util::AssertMainTabCount(2);
+ // Switch between the two tabs. Both are currently in memory.
+ chrome_test_util::SelectTabAtIndexInCurrentMode(0);
+
+ // Verify that one in-memory tab switch has been recorded.
+ // histogramTester.ExpectTotalCount(kSelectedTabHistogramName, 1,
+ // failureBlock);
+ histogramTester.ExpectUniqueSample(
+ kSelectedTabHistogramName, TabUsageRecorder::IN_MEMORY, 1, failureBlock);
+
+ // Evict the tab.
+ OpenNewIncognitoTabUsingUIAndEvictMainTabs();
+ GREYAssertTrue(chrome_test_util::IsIncognitoMode(),
+ @"Failed to switch to incognito mode");
+
+ // Switch back to the normal tabs. Should be on tab one.
+ SwitchToNormalMode();
+ [[EarlGrey selectElementWithMatcher:chrome_test_util::webViewContainingText(
+ kURL1FirstWord)]
+ assertWithMatcher:grey_notNil()];
+
+ histogramTester.ExpectTotalCount(kSelectedTabHistogramName, 2, failureBlock);
+ histogramTester.ExpectBucketCount(kSelectedTabHistogramName,
+ TabUsageRecorder::EVICTED, 1, failureBlock);
+}
+
+// Verifies the UMA metric for page loads before a tab eviction by loading
+// some tabs, forcing a tab eviction, then checking the histogram.
+- (void)testPageLoadCountBeforeEvictedTab {
+ web::test::SetUpFileBasedHttpServer();
+ chrome_test_util::HistogramTester histogramTester;
+ ResetTabUsageRecorder();
+ const GURL url1 = web::test::HttpServer::MakeUrl(kTestUrl1);
+ FailureBlock failureBlock = ^(NSString* error) {
+ GREYFail(error);
+ };
+
+ // This test opens three tabs.
+ const int numberOfTabs = 3;
+ chrome_test_util::CloseAllTabsInCurrentMode();
+ // Open three tabs with http:// urls.
+ for (NSUInteger i = 0; i < numberOfTabs; i++) {
+ chrome_test_util::OpenNewTab();
+ [ChromeEarlGrey loadURL:url1];
+ [[EarlGrey selectElementWithMatcher:chrome_test_util::webViewContainingText(
+ kURL1FirstWord)]
+ assertWithMatcher:grey_notNil()];
+ }
+ chrome_test_util::AssertMainTabCount(numberOfTabs);
+
+ // Switch between the tabs. They are currently in memory.
+ chrome_test_util::SelectTabAtIndexInCurrentMode(0);
+
+ // Verify that no page-load count has been recorded.
+ histogramTester.ExpectTotalCount(kPageLoadsBeforeEvictedTabSelected, 0,
+ failureBlock);
+
+ // Reload each tab.
+ for (NSUInteger i = 0; i < numberOfTabs; i++) {
+ chrome_test_util::SelectTabAtIndexInCurrentMode(i);
+ // Clear the page so that we can check when pade reload is complete.
+ __block bool finished = false;
+ chrome_test_util::GetCurrentWebState()->ExecuteJavaScript(
+ base::UTF8ToUTF16(kClearPageScript),
+ base::BindBlock(^(const base::Value*) {
+ finished = true;
+ }));
+
+ GREYAssert(testing::WaitUntilConditionOrTimeout(1.0,
+ ^{
+ return finished;
+ }),
+ @"JavaScript to reload each tab did not finish");
+ [ChromeEarlGreyUI reload];
+ [[EarlGrey selectElementWithMatcher:chrome_test_util::webViewContainingText(
+ kURL1FirstWord)]
+ assertWithMatcher:grey_notNil()];
+ }
+
+ // Evict the tab. Create a dummy tab so that switching back to normal mode
+ // does not trigger a reload immediatly.
+ chrome_test_util::OpenNewTab();
+ OpenNewIncognitoTabUsingUIAndEvictMainTabs();
+ chrome_test_util::AssertIncognitoTabCount(1);
+
+ // Switch back to the normal tabs. Should be on tab one.
+ SwitchToNormalMode();
+ chrome_test_util::SelectTabAtIndexInCurrentMode(0);
+ [[EarlGrey selectElementWithMatcher:chrome_test_util::webViewContainingText(
+ kURL1FirstWord)]
+ assertWithMatcher:grey_notNil()];
+
+ // Verify that one page-load count has been recorded. It should contain two
+ // page loads for each tab created.
+ histogramTester.ExpectTotalCount(kPageLoadsBeforeEvictedTabSelected, 1,
+ failureBlock);
+
+ std::unique_ptr<base::HistogramSamples> samples =
+ histogramTester.GetHistogramSamplesSinceCreation(
+ kPageLoadsBeforeEvictedTabSelected);
+ int sampleSum = samples ? samples->sum() : 0;
+ GREYAssertEqual(
+ sampleSum, numberOfTabs * 2,
+ [NSString stringWithFormat:@"Expected page loads is %d, actual %d.",
+ numberOfTabs * 2, sampleSum]);
+}
+
+// Tests that tabs reloaded on cold start are reported as
+// EVICTED_DUE_TO_COLD_START.
+- (void)testColdLaunchReloadCount {
+ web::test::SetUpFileBasedHttpServer();
+ chrome_test_util::HistogramTester histogramTester;
+ ResetTabUsageRecorder();
+
+ // Open two tabs with urls.
+ OpenTwoTabs();
+ chrome_test_util::AssertMainTabCount(2);
+ // Set the normal tabs as 'cold start' tabs.
+ GREYAssertTrue(chrome_test_util::SetCurrentTabsToBeColdStartTabs(),
+ @"Fail to state tabs as cold start tabs");
+
+ // Open two incognito tabs with urls, clearing normal tabs from memory.
+ OpenNewIncognitoTabUsingUIAndEvictMainTabs();
+ OpenNewIncognitoTabUsingUIAndEvictMainTabs();
+ chrome_test_util::AssertIncognitoTabCount(2);
+
+ // Switch back to the normal tabs.
+ SwitchToNormalMode();
+ [[EarlGrey selectElementWithMatcher:chrome_test_util::webViewContainingText(
+ kURL2FirstWord)]
+ assertWithMatcher:grey_notNil()];
+
+ // Select the other one so it also reloads.
+ chrome_test_util::SelectTabAtIndexInCurrentMode(0);
+ [[EarlGrey selectElementWithMatcher:chrome_test_util::webViewContainingText(
+ kURL1FirstWord)]
+ assertWithMatcher:grey_notNil()];
+
+ FailureBlock failureBlock = ^(NSString* error) {
+ GREYFail(error);
+ };
+ // Make sure that one of the 2 tab loads (excluding the selected tab) is
+ // counted as a cold start eviction.
+ histogramTester.ExpectBucketCount(kSelectedTabHistogramName,
+ TabUsageRecorder::EVICTED_DUE_TO_COLD_START,
+ 1, failureBlock);
+
+ histogramTester.ExpectBucketCount(
+ kSelectedTabHistogramName, TabUsageRecorder::IN_MEMORY, 0, failureBlock);
+ // Re-select the same tab and make sure it is not counted again as evicted.
+ chrome_test_util::SelectTabAtIndexInCurrentMode(1);
+ chrome_test_util::SelectTabAtIndexInCurrentMode(0);
+
+ [[EarlGrey selectElementWithMatcher:chrome_test_util::webViewContainingText(
+ kURL1FirstWord)]
+ assertWithMatcher:grey_notNil()];
+ histogramTester.ExpectBucketCount(kSelectedTabHistogramName,
+ TabUsageRecorder::EVICTED_DUE_TO_COLD_START,
+ 1, failureBlock);
+
+ histogramTester.ExpectBucketCount(
+ kSelectedTabHistogramName, TabUsageRecorder::IN_MEMORY, 2, failureBlock);
+}
+
+// Tests that tabs reloads after backgrounding and eviction.
+- (void)testBackgroundingReloadCount {
+ web::test::SetUpFileBasedHttpServer();
+ chrome_test_util::HistogramTester histogramTester;
+ ResetTabUsageRecorder();
+ FailureBlock failureBlock = ^(NSString* error) {
+ GREYFail(error);
+ };
+
+ // Open two tabs with urls.
+ OpenTwoTabs();
+ chrome_test_util::AssertMainTabCount(2);
+
+ // Simulate going into the background.
+ GREYAssertTrue(chrome_test_util::SimulateTabsBackgrounding(),
+ @"Fail to simulate tab backgrounding.");
+
+ // Open incognito and clear normal tabs from memory.
+ OpenNewIncognitoTabUsingUIAndEvictMainTabs();
+ GREYAssertTrue(chrome_test_util::IsIncognitoMode(),
+ @"Failed to switch to incognito mode");
+ histogramTester.ExpectTotalCount(kEvictedTabReloadTime, 0, failureBlock);
+
+ // Switch back to the normal tabs.
+ SwitchToNormalMode();
+ [[EarlGrey selectElementWithMatcher:chrome_test_util::webViewContainingText(
+ kURL2FirstWord)]
+ assertWithMatcher:grey_notNil()];
+
+ const GURL url1 = web::test::HttpServer::MakeUrl(kTestUrl1);
+ const GURL url2 = web::test::HttpServer::MakeUrl(kTestUrl2);
+ [[EarlGrey
+ selectElementWithMatcher:chrome_test_util::omniboxText(url2.GetContent())]
+ assertWithMatcher:grey_notNil()];
+ histogramTester.ExpectTotalCount(kEvictedTabReloadTime, 1, failureBlock);
+
+ chrome_test_util::SelectTabAtIndexInCurrentMode(0);
+ [[EarlGrey selectElementWithMatcher:chrome_test_util::webViewContainingText(
+ kURL1FirstWord)]
+ assertWithMatcher:grey_notNil()];
+ [[EarlGrey
+ selectElementWithMatcher:chrome_test_util::omniboxText(url1.GetContent())]
+ assertWithMatcher:grey_notNil()];
+ histogramTester.ExpectTotalCount(kEvictedTabReloadTime, 2, failureBlock);
+}
+
+// Verify correct recording of metrics when the reloading of an evicted tab
+// succeeds.
+- (void)testEvictedTabReloadSuccess {
+ web::test::SetUpFileBasedHttpServer();
+ chrome_test_util::HistogramTester histogramTester;
+ FailureBlock failureBlock = ^(NSString* error) {
+ GREYFail(error);
+ };
+
+ GURL URL = web::test::HttpServer::MakeUrl(kTestUrl1);
+ NewMainTabWithURL(URL, kURL1FirstWord);
+ OpenNewIncognitoTabUsingUIAndEvictMainTabs();
+ SwitchToNormalMode();
+ [[EarlGrey selectElementWithMatcher:chrome_test_util::webViewContainingText(
+ kURL1FirstWord)]
+ assertWithMatcher:grey_notNil()];
+
+ histogramTester.ExpectUniqueSample(kEvictedTabReloadSuccessRate,
+ TabUsageRecorder::LOAD_SUCCESS, 1,
+ failureBlock);
+ histogramTester.ExpectUniqueSample(kDidUserWaitForEvictedTabReload,
+ TabUsageRecorder::USER_WAITED, 1,
+ failureBlock);
+ histogramTester.ExpectTotalCount(kEvictedTabReloadTime, 1, failureBlock);
+}
+
+// Verify correct recording of metrics when the reloading of an evicted tab
+// fails.
+- (void)testEvictedTabReloadFailure {
+ web::test::SetUpFileBasedHttpServer();
+ chrome_test_util::HistogramTester histogramTester;
+ FailureBlock failureBlock = ^(NSString* error) {
+ GREYFail(error);
+ };
+
+ // This URL is purposely invalid so it triggers a navigation error.
+ GURL invalidURL(kTestUrl1);
+
+ chrome_test_util::OpenNewTab();
+ [ChromeEarlGrey loadURL:invalidURL];
+ CheckErrorPageIsVisible();
+ OpenNewIncognitoTabUsingUIAndEvictMainTabs();
+
+ SwitchToNormalMode();
+ CheckErrorPageIsVisible();
+
+ histogramTester.ExpectUniqueSample(kEvictedTabReloadSuccessRate,
+ TabUsageRecorder::LOAD_FAILURE, 1,
+ failureBlock);
+ histogramTester.ExpectUniqueSample(kDidUserWaitForEvictedTabReload,
+ TabUsageRecorder::USER_WAITED, 1,
+ failureBlock);
+ histogramTester.ExpectTotalCount(kEvictedTabReloadTime, 0, failureBlock);
+}
+
+// Test that USER_DID_NOT_WAIT is reported if the user does not wait for the
+// reload to be complete after eviction.
+- (void)testEvictedTabSlowReload {
+ std::map<GURL, std::string> responses;
+ const GURL slowURL = web::test::HttpServer::MakeUrl("http://slow");
+ responses[slowURL] = "Slow Page";
+
+ web::test::SetUpHttpServer(base::MakeUnique<web::DelayedResponseProvider>(
+ base::MakeUnique<HtmlResponseProvider>(responses), kSlowURLDelay));
+
+ chrome_test_util::HistogramTester histogramTester;
+ FailureBlock failureBlock = ^(NSString* error) {
+ GREYFail(error);
+ };
+
+ // A blank tab needed to switch to it after reloading.
+ chrome_test_util::OpenNewTab();
+ chrome_test_util::OpenNewTab();
+ chrome_test_util::LoadUrl(slowURL);
+ OpenNewIncognitoTabUsingUIAndEvictMainTabs();
+
+ web::test::SetUpHttpServer(base::MakeUnique<web::DelayedResponseProvider>(
+ base::MakeUnique<HtmlResponseProvider>(responses), kSlowURLDelay));
+
+ SwitchToNormalMode();
+
+ GREYAssert(
+ [[GREYCondition conditionWithName:@"Wait for tab to restart loading."
+ block:^BOOL() {
+ return chrome_test_util::IsLoading();
+ }] waitWithTimeout:kWaitElementTimeout],
+ @"Tab did not start loading.");
+
+ // This method is not synced on EarlGrey.
+ chrome_test_util::SelectTabAtIndexInCurrentMode(0);
+
+ // Do not test the kEvictedTabReloadSuccessRate, as the timing of the two
+ // page loads cannot be guaranteed. The test would be flaky.
+ histogramTester.ExpectBucketCount(kDidUserWaitForEvictedTabReload,
+ TabUsageRecorder::USER_DID_NOT_WAIT, 1,
+ failureBlock);
+}
+
+// Test that the USER_DID_NOT_WAIT metric is logged when the user opens an NTP
+// while the evicted tab is still reloading.
+- (void)testEvictedTabReloadSwitchToNTP {
+ std::map<GURL, std::string> responses;
+ const GURL slowURL = web::test::HttpServer::MakeUrl("http://slow");
+ responses[slowURL] = "Slow Page";
+
+ web::test::SetUpHttpServer(base::MakeUnique<HtmlResponseProvider>(responses));
+
+ chrome_test_util::HistogramTester histogramTester;
+ FailureBlock failureBlock = ^(NSString* error) {
+ GREYFail(error);
+ };
+
+ NewMainTabWithURL(slowURL, "Slow");
+
+ OpenNewIncognitoTabUsingUIAndEvictMainTabs();
+ web::test::SetUpHttpServer(base::MakeUnique<web::DelayedResponseProvider>(
+ base::MakeUnique<HtmlResponseProvider>(responses), kSlowURLDelay));
+
+ SwitchToNormalMode();
+
+ // TODO(crbug.com/640977): EarlGrey synchronize on some animations when a
+ // page is loading. Need to handle synchronization manually for this test.
+ [[GREYConfiguration sharedInstance]
+ setValue:@(NO)
+ forConfigKey:kGREYConfigKeySynchronizationEnabled];
+ OpenNewMainTabUsingUIUnsynced();
+ [[GREYConfiguration sharedInstance]
+ setValue:@(YES)
+ forConfigKey:kGREYConfigKeySynchronizationEnabled];
+ histogramTester.ExpectBucketCount(kDidUserWaitForEvictedTabReload,
+ TabUsageRecorder::USER_DID_NOT_WAIT, 1,
+ failureBlock);
+}
+
+// Test that the USER_DID_NOT_WAIT metric is not logged when the user opens
+// and closes the settings UI while the evicted tab is still reloading.
+- (void)testEvictedTabReloadSettingsAndBack {
+ std::map<GURL, std::string> responses;
+ const GURL slowURL = web::test::HttpServer::MakeUrl("http://slow");
+ responses[slowURL] = "Slow Page";
+
+ web::test::SetUpHttpServer(base::MakeUnique<web::DelayedResponseProvider>(
+ base::MakeUnique<HtmlResponseProvider>(responses), kSlowURLDelay));
+
+ chrome_test_util::HistogramTester histogramTester;
+ FailureBlock failureBlock = ^(NSString* error) {
+ GREYFail(error);
+ };
+
+ NewMainTabWithURL(slowURL, responses[slowURL]);
+
+ OpenNewIncognitoTabUsingUIAndEvictMainTabs();
+
+ SwitchToNormalMode();
+ // TODO(crbug.com/640977): EarlGrey synchronize on some animations when a
+ // page is loading. Need to handle synchronization manually for this test.
+ [[GREYConfiguration sharedInstance]
+ setValue:@(NO)
+ forConfigKey:kGREYConfigKeySynchronizationEnabled];
+ OpenSettingsMenuUnsynced();
+ OpenSettingsSubMenuUnsynced(IDS_OPTIONS_ADVANCED_SECTION_TITLE_PRIVACY);
+ Wait(grey_accessibilityID(kPrivacyCollectionViewId),
+ @"Privacy settings view.");
+
+ WaitAndTap(grey_accessibilityLabel(
+ l10n_util::GetNSString(IDS_IOS_NAVIGATION_BAR_DONE_BUTTON)),
+ @"Close settings");
+ [[GREYUIThreadExecutor sharedInstance] drainUntilIdle];
+ [[EarlGrey selectElementWithMatcher:chrome_test_util::webViewContainingText(
+ responses[slowURL])]
+ assertWithMatcher:grey_notNil()];
+
+ [[GREYConfiguration sharedInstance]
+ setValue:@(YES)
+ forConfigKey:kGREYConfigKeySynchronizationEnabled];
+
+ histogramTester.ExpectBucketCount(kDidUserWaitForEvictedTabReload,
+ TabUsageRecorder::USER_DID_NOT_WAIT, 0,
+ failureBlock);
+ histogramTester.ExpectBucketCount(kDidUserWaitForEvictedTabReload,
+ TabUsageRecorder::USER_WAITED, 1,
+ failureBlock);
+}
+
+// Tests that leaving Chrome while an evicted tab is reloading triggers the
+// recording of the USER_LEFT_CHROME metric.
+- (void)testEvictedTabReloadBackgrounded {
+ std::map<GURL, std::string> responses;
+ const GURL slowURL = web::test::HttpServer::MakeUrl("http://slow");
+ responses[slowURL] = "Slow Page";
+
+ web::test::SetUpHttpServer(base::MakeUnique<HtmlResponseProvider>(responses));
+
+ chrome_test_util::HistogramTester histogramTester;
+ chrome_test_util::OpenNewTab();
+ chrome_test_util::LoadUrl(slowURL);
+
+ OpenNewIncognitoTabUsingUIAndEvictMainTabs();
+
+ web::test::SetUpHttpServer(base::MakeUnique<web::DelayedResponseProvider>(
+ base::MakeUnique<HtmlResponseProvider>(responses), kSlowURLDelay));
+ SwitchToNormalMode();
+
+ // TODO(crbug.com/640977): EarlGrey synchronize on some animations when a
+ // page is loading. Need to handle synchronization manually for this test.
+ [[GREYConfiguration sharedInstance]
+ setValue:@(NO)
+ forConfigKey:kGREYConfigKeySynchronizationEnabled];
+ id<GREYMatcher> toolMenuMatcher =
+ grey_accessibilityID(kToolbarToolsMenuButtonIdentifier);
+ Wait(toolMenuMatcher, @"Tool Menu");
+
+ GREYAssertTrue(chrome_test_util::SimulateTabsBackgrounding(),
+ @"Failed to simulate tab backgrounding.");
+ [[GREYConfiguration sharedInstance]
+ setValue:@(YES)
+ forConfigKey:kGREYConfigKeySynchronizationEnabled];
+
+ FailureBlock failureBlock = ^(NSString* error) {
+ GREYFail(error);
+ };
+ histogramTester.ExpectBucketCount(kDidUserWaitForEvictedTabReload,
+ TabUsageRecorder::USER_LEFT_CHROME, 1,
+ failureBlock);
+}
+
+// Tests that backgrounding a tab that was not evicted while it is loading does
+// not record the USER_LEFT_CHROME metric.
+- (void)testLiveTabReloadBackgrounded {
+ std::map<GURL, std::string> responses;
+ const GURL slowURL = web::test::HttpServer::MakeUrl("http://slow");
+ responses[slowURL] = "Slow Page";
+
+ web::test::SetUpHttpServer(base::MakeUnique<web::DelayedResponseProvider>(
+ base::MakeUnique<HtmlResponseProvider>(responses), kSlowURLDelay));
+
+ chrome_test_util::HistogramTester histogramTester;
+
+ // We need two tabs to be able to switch.
+ chrome_test_util::OpenNewTab();
+ [[GREYConfiguration sharedInstance]
+ setValue:@(NO)
+ forConfigKey:kGREYConfigKeySynchronizationEnabled];
+ chrome_test_util::LoadUrl(slowURL);
+
+ // Ensure loading starts but is not finished.
+ base::test::ios::SpinRunLoopWithMaxDelay(base::TimeDelta::FromSeconds(1));
+ chrome_test_util::SelectTabAtIndexInCurrentMode(0);
+ [[GREYConfiguration sharedInstance]
+ setValue:@(YES)
+ forConfigKey:kGREYConfigKeySynchronizationEnabled];
+
+ FailureBlock failureBlock = ^(NSString* error) {
+ GREYFail(error);
+ };
+ histogramTester.ExpectBucketCount(kDidUserWaitForEvictedTabReload,
+ TabUsageRecorder::USER_LEFT_CHROME, 0,
+ failureBlock);
+}
+
+// Tests that redirecting pages are not reloaded after eviction.
+- (void)testPageRedirect {
+ GURL redirectURL = web::test::HttpServer::MakeUrl(
+ "http://ios/testing/data/http_server_files/redirect_refresh.html");
+ GURL destinationURL = web::test::HttpServer::MakeUrl(
+ "http://ios/testing/data/http_server_files/destination.html");
+ web::test::SetUpFileBasedHttpServer();
+ chrome_test_util::HistogramTester histogramTester;
+ ResetTabUsageRecorder();
+
+ NewMainTabWithURL(redirectURL, "arrived");
+
+ [[EarlGrey selectElementWithMatcher:chrome_test_util::omniboxText(
+ destinationURL.GetContent())]
+ assertWithMatcher:grey_notNil()];
+
+ NSUInteger tabIndex = chrome_test_util::GetMainTabCount() - 1;
+ chrome_test_util::OpenNewTab();
+ OpenNewIncognitoTabUsingUIAndEvictMainTabs();
+ SwitchToNormalMode();
+ chrome_test_util::SelectTabAtIndexInCurrentMode(tabIndex);
+ [[EarlGrey selectElementWithMatcher:chrome_test_util::webViewContainingText(
+ "arrived")]
+ assertWithMatcher:grey_notNil()];
+
+ FailureBlock failureBlock = ^(NSString* error) {
+ GREYFail(error);
+ };
+ // Verify that one page-load count has been recorded. It should contain a
+ // sum of 1 - one sample with 1 page load.
+ histogramTester.ExpectTotalCount(kPageLoadsBeforeEvictedTabSelected, 1,
+ failureBlock);
+
+ std::unique_ptr<base::HistogramSamples> samples =
+ histogramTester.GetHistogramSamplesSinceCreation(
+ kPageLoadsBeforeEvictedTabSelected);
+ int sampleSum = samples->sum();
+ GREYAssertEqual(
+ sampleSum, 1,
+ [NSString stringWithFormat:@"Expected page loads is %d, actual is %d.", 1,
+ sampleSum]);
+}
+
+// Tests that navigations are correctly reported in
+// Tab.PageLoadsSinceLastSwitchToEvictedTab histogram.
+- (void)testLinkClickNavigation {
+ // Create map of canned responses and set up the test HTML server.
+ std::map<GURL, std::string> responses;
+ const GURL initialURL =
+ web::test::HttpServer::MakeUrl("http://scenarioTestLinkClickNavigation");
+ const GURL destinationURL =
+ web::test::HttpServer::MakeUrl("http://destination");
+ responses[initialURL] = base::StringPrintf(
+ "<body><a style='margin-left:50px' href='%s' id='link'>link</a></body>",
+ destinationURL.spec().c_str());
+ responses[destinationURL] = "Whee!";
+ web::test::SetUpHttpServer(base::MakeUnique<HtmlResponseProvider>(responses));
+ chrome_test_util::HistogramTester histogramTester;
+ ResetTabUsageRecorder();
+
+ // Open a tab with a link to click.
+ NewMainTabWithURL(initialURL, "link");
+ // Click the link.
+ chrome_test_util::TapWebViewElementWithId("link");
+
+ [[EarlGrey
+ selectElementWithMatcher:chrome_test_util::webViewContainingText("Whee")]
+ assertWithMatcher:grey_notNil()];
+
+ NSUInteger tabIndex = chrome_test_util::GetMainTabCount() - 1;
+ chrome_test_util::OpenNewTab();
+ OpenNewIncognitoTabUsingUIAndEvictMainTabs();
+ SwitchToNormalMode();
+ chrome_test_util::SelectTabAtIndexInCurrentMode(tabIndex);
+ [[EarlGrey
+ selectElementWithMatcher:chrome_test_util::webViewContainingText("Whee")]
+ assertWithMatcher:grey_notNil()];
+
+ // Verify that the page-load count has been recorded. It should contain a
+ // sum of 2 - one sample with 2 page loads.
+ std::unique_ptr<base::HistogramSamples> samples =
+ histogramTester.GetHistogramSamplesSinceCreation(
+ kPageLoadsBeforeEvictedTabSelected);
+ int sampleSum = samples->sum();
+ GREYAssertEqual(
+ sampleSum, 2,
+ [NSString stringWithFormat:@"Expected page loads is %d, actual %d.", 2,
+ sampleSum]);
+
+ FailureBlock failureBlock = ^(NSString* error) {
+ GREYFail(error);
+ };
+ // Verify that only one evicted tab was selected. This is to make sure the
+ // link click did not generate an evicted-tab-reload count.
+ histogramTester.ExpectBucketCount(kSelectedTabHistogramName,
+ TabUsageRecorder::EVICTED, 1, failureBlock);
+}
+
+// Tests that opening links in a new tab will not evict the source tab.
+- (void)testOpenLinkInNewTab {
+ // Create map of canned responses and set up the test HTML server.
+ std::map<GURL, std::string> responses;
+ const GURL initialURL =
+ web::test::HttpServer::MakeUrl("http://scenarioTestOpenLinkInNewTab");
+ const GURL destinationURL =
+ web::test::HttpServer::MakeUrl("http://destination");
+ // Make the link that cover the whole page so that long pressing the web view
+ // will trigger the link context menu.
+ responses[initialURL] = base::StringPrintf(
+ "<body style='width:auto; height:auto;'><a href='%s' "
+ "id='link'><div style='width:100%%; "
+ "height:100%%;'>link</div></a></body>",
+ destinationURL.spec().c_str());
+ responses[destinationURL] = "Whee!";
+ web::test::SetUpHttpServer(base::MakeUnique<HtmlResponseProvider>(responses));
+ chrome_test_util::HistogramTester histogramTester;
+ ResetTabUsageRecorder();
+
+ // Open a tab with a link to click.
+ NewMainTabWithURL(initialURL, "link");
+
+ int numberOfTabs = chrome_test_util::GetMainTabCount();
+ [[EarlGrey
+ selectElementWithMatcher:chrome_test_util::webViewContainingText("link")]
+ performAction:grey_longPress()];
+
+ [[EarlGrey
+ selectElementWithMatcher:grey_text(l10n_util::GetNSString(
+ IDS_IOS_CONTENT_CONTEXT_OPENLINKNEWTAB))]
+ performAction:grey_tap()];
+ chrome_test_util::AssertMainTabCount(numberOfTabs + 1);
+
+ SelectTabUsingUI(base::SysUTF8ToNSString(destinationURL.GetContent()));
+
+ [[GREYUIThreadExecutor sharedInstance] drainUntilIdle];
+ [[EarlGrey
+ selectElementWithMatcher:chrome_test_util::webViewContainingText("Whee")]
+ assertWithMatcher:grey_notNil()];
+
+ FailureBlock failureBlock = ^(NSString* error) {
+ GREYFail(error);
+ };
+ histogramTester.ExpectTotalCount(kSelectedTabHistogramName, 1, failureBlock);
+ histogramTester.ExpectBucketCount(
+ kSelectedTabHistogramName, TabUsageRecorder::IN_MEMORY, 1, failureBlock);
+}
+
+// Tests that opening tabs from external app will not cause tab eviction.
+- (void)testOpenFromApp {
+ web::test::SetUpFileBasedHttpServer();
+ chrome_test_util::HistogramTester histogramTester;
+ ResetTabUsageRecorder();
+
+ chrome_test_util::OpenNewTab();
+ GURL url(kTestUrl1);
+
+ chrome_test_util::OpenChromeFromExternalApp(url);
+
+ // Add a delay to ensure the tab has fully opened. Because the check below
+ // is for zero metrics recorded, it adds no flakiness. However, this pause
+ // makes the step more likely to fail in failure cases. I.e. without it, this
+ // test would sometimes pass even when it should fail.
+ base::test::ios::SpinRunLoopWithMaxDelay(
+ base::TimeDelta::FromMilliseconds(500));
+
+ FailureBlock failureBlock = ^(NSString* error) {
+ GREYFail(error);
+ };
+ // Verify that zero Tab.StatusWhenSwitchedBackToForeground metrics were
+ // recorded. Tabs created at the time the user switches to them should not
+ // be counted in this metric.
+ histogramTester.ExpectTotalCount(kSelectedTabHistogramName, 0, failureBlock);
+}
+
+// Verify that evicted tabs that are deleted are removed from the evicted tabs
+// map.
+- (void)testTabDeletion {
+ web::test::SetUpFileBasedHttpServer();
+ chrome_test_util::HistogramTester histogramTester;
+ ResetTabUsageRecorder();
+ // Add an autorelease pool to delete the closed tabs before the end of the
+ // test.
+ @autoreleasepool {
+ // Open two tabs with urls.
+ OpenTwoTabs();
+ // Set the normal tabs as 'cold start' tabs.
+ chrome_test_util::SetCurrentTabsToBeColdStartTabs();
+ // One more tab.
+ const GURL url1 = web::test::HttpServer::MakeUrl(kTestUrl1);
+ NewMainTabWithURL(url1, kURL1FirstWord);
+
+ GREYAssertEqual(chrome_test_util::GetMainTabCount(), 3,
+ @"Check number of normal tabs");
+ // The cold start tab which was not active will still be evicted.
+ GREYAssertEqual(chrome_test_util::GetEvictedMainTabCount(), 1,
+ @"Check number of evicted tabs");
+
+ // Close two of the three open tabs without selecting them first.
+ // This should delete the tab objects, even though they're still being
+ // tracked
+ // by the tab usage recorder in its |evicted_tabs_| map.
+ CloseTabAtIndexAndSync(1);
+
+ GREYAssertEqual(chrome_test_util::GetMainTabCount(), 2,
+ @"Check number of normal tabs");
+ CloseTabAtIndexAndSync(0);
+ GREYAssertEqual(chrome_test_util::GetMainTabCount(), 1,
+ @"Check number of normal tabs");
+ [[GREYUIThreadExecutor sharedInstance] drainUntilIdle];
+ }
+ // The deleted tabs are purged during foregrounding and backgrounding.
+ chrome_test_util::SimulateTabsBackgrounding();
+ // Make sure |evicted_tabs_| purged the deleted tabs.
+ int evicted = chrome_test_util::GetEvictedMainTabCount();
+ GREYAssertEqual(evicted, 0, @"Check number of evicted tabs");
+}
+
+@end
« 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