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

Unified Diff: ios/chrome/browser/metrics/tab_usage_recorder_unittest.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_unittest.mm
diff --git a/ios/chrome/browser/metrics/tab_usage_recorder_unittest.mm b/ios/chrome/browser/metrics/tab_usage_recorder_unittest.mm
new file mode 100644
index 0000000000000000000000000000000000000000..ccd9cd22ef5268bb9835885960e0f468c8e49f41
--- /dev/null
+++ b/ios/chrome/browser/metrics/tab_usage_recorder_unittest.mm
@@ -0,0 +1,366 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <memory>
+
+#include "base/mac/scoped_nsobject.h"
+#include "base/message_loop/message_loop.h"
+#include "base/metrics/histogram_samples.h"
+#include "base/stl_util.h"
+#include "base/test/histogram_tester.h"
+#import "ios/chrome/browser/metrics/previous_session_info.h"
+#include "ios/chrome/browser/metrics/tab_usage_recorder.h"
+#import "ios/chrome/browser/metrics/tab_usage_recorder_delegate.h"
+#import "ios/chrome/browser/tabs/tab.h"
+#include "ios/testing/ocmock_complex_type_helper.h"
+#include "ios/web/public/test/test_web_thread.h"
+#import "ios/web/web_state/ui/crw_web_controller.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/platform_test.h"
+#include "third_party/ocmock/ocmock_extensions.h"
+
+@interface TURTestTabMock : OCMockComplexTypeHelper {
+ GURL _url;
+}
+
+@property(nonatomic, assign) const GURL& url;
+@end
+
+@implementation TURTestTabMock
+- (const GURL&)url {
+ return _url;
+}
+- (void)setUrl:(const GURL&)url {
+ _url = url;
+}
+@end
+
+// A mock TabUsageRecorderDelegate which allows the unit tests to control
+// the count of live tabs returned from the |liveTabsCount| delegate method.
+@interface MockTabUsageRecorderDelegate : NSObject<TabUsageRecorderDelegate> {
+ NSUInteger _tabCount;
+}
+
+// Sets the live tab count returned from the |liveTabsCount| delegate method.
+- (void)setLiveTabsCount:(NSUInteger)count;
+
+@end
+
+@implementation MockTabUsageRecorderDelegate
+
+- (void)setLiveTabsCount:(NSUInteger)count {
+ _tabCount = count;
+}
+
+- (NSUInteger)liveTabsCount {
+ return _tabCount;
+}
+
+@end
+
+namespace {
+
+// The number of alive tabs at a renderer termination used by unit test.
+const NSUInteger kAliveTabsCountAtRendererTermination = 2U;
+
+// The number of timestamps added to the renderer termination timestamp list
+// that are not counted in the RecentlyAliveTabs metric.
+const int kExpiredTimesAddedCount = 2;
+
+class TabUsageRecorderForTesting : public TabUsageRecorder {
+ public:
+ TabUsageRecorderForTesting(MockTabUsageRecorderDelegate* delegate)
+ : TabUsageRecorder(delegate) {}
+ // For testing only.
+ base::TimeTicks RestoreStartTime() const { return restore_start_time_; }
+
+ // Adds |time| to the deque keeping track of renderer termination
+ // timestamps.
+ void AddTimeToDeque(base::TimeTicks time) {
+ termination_timestamps_.push_back(time);
+ }
+};
+
+class TabUsageRecorderTest : public PlatformTest {
+ protected:
+ void SetUp() override {
+ loop_.reset(new base::MessageLoop(base::MessageLoop::TYPE_DEFAULT));
+ ui_thread_.reset(new web::TestWebThread(web::WebThread::UI, loop_.get()));
+ histogram_tester_.reset(new base::HistogramTester());
+ // Set the delegate to nil to allow the relevant unit tests direct access to
+ // the mock delegate.
+ tab_usage_recorder_.reset(new TabUsageRecorderForTesting(nil));
+ webUrl_ = GURL("http://www.chromium.org");
+ nativeUrl_ = GURL("chrome://version");
+ }
+
+ id MockTab(bool inMemory) {
+ id tab_mock = [[TURTestTabMock alloc]
+ initWithRepresentedObject:[OCMockObject mockForClass:[Tab class]]];
+ id web_controller_mock =
+ [OCMockObject mockForClass:[CRWWebController class]];
+ [[[tab_mock stub] andReturn:web_controller_mock] webController];
+ [[[tab_mock stub] andReturnBool:false] isPrerenderTab];
+ [tab_mock setUrl:webUrl_];
+ [[[web_controller_mock stub] andReturnBool:inMemory] isViewAlive];
+ [[web_controller_mock stub] removeObserver:OCMOCK_ANY];
+ return [tab_mock autorelease];
+ }
+
+ GURL webUrl_;
+ GURL nativeUrl_;
+ std::unique_ptr<base::MessageLoop> loop_;
+ std::unique_ptr<web::TestWebThread> ui_thread_;
+ std::unique_ptr<base::HistogramTester> histogram_tester_;
+ std::unique_ptr<TabUsageRecorderForTesting> tab_usage_recorder_;
+};
+
+TEST_F(TabUsageRecorderTest, SwitchBetweenInMemoryTabs) {
+ id tab_mock_a = MockTab(true);
+ id tab_mock_b = MockTab(true);
+
+ tab_usage_recorder_->RecordTabSwitched(tab_mock_a, tab_mock_b);
+ histogram_tester_->ExpectUniqueSample(kSelectedTabHistogramName,
+ TabUsageRecorder::IN_MEMORY, 1);
+}
+
+TEST_F(TabUsageRecorderTest, SwitchToEvictedTab) {
+ id tab_mock_a = MockTab(true);
+ id tab_mock_b = MockTab(false);
+
+ tab_usage_recorder_->RecordTabSwitched(tab_mock_a, tab_mock_b);
+ histogram_tester_->ExpectUniqueSample(kSelectedTabHistogramName,
+ TabUsageRecorder::EVICTED, 1);
+}
+
+TEST_F(TabUsageRecorderTest, SwitchFromEvictedTab) {
+ id tab_mock_a = MockTab(false);
+ id tab_mock_b = MockTab(true);
+
+ tab_usage_recorder_->RecordTabSwitched(tab_mock_a, tab_mock_b);
+ histogram_tester_->ExpectUniqueSample(kSelectedTabHistogramName,
+ TabUsageRecorder::IN_MEMORY, 1);
+}
+
+TEST_F(TabUsageRecorderTest, SwitchBetweenEvictedTabs) {
+ id tab_mock_a = MockTab(false);
+ id tab_mock_b = MockTab(false);
+
+ tab_usage_recorder_->RecordTabSwitched(tab_mock_a, tab_mock_b);
+ histogram_tester_->ExpectUniqueSample(kSelectedTabHistogramName,
+ TabUsageRecorder::EVICTED, 1);
+}
+
+TEST_F(TabUsageRecorderTest, CountPageLoadsBeforeEvictedTab) {
+ id tab_mock_a = MockTab(true);
+ id tab_mock_b = MockTab(false);
+
+ // Call reload an arbitrary number of times.
+ const int kNumReloads = 4;
+ for (int i = 0; i < kNumReloads; i++) {
+ tab_usage_recorder_->RecordPageLoadStart(tab_mock_a);
+ }
+ tab_usage_recorder_->RecordTabSwitched(tab_mock_a, tab_mock_b);
+ histogram_tester_->ExpectUniqueSample(kPageLoadsBeforeEvictedTabSelected,
+ kNumReloads, 1);
+}
+
+TEST_F(TabUsageRecorderTest, CountNativePageLoadsBeforeEvictedTab) {
+ id tab_mock_a = MockTab(true);
+ id tab_mock_b = MockTab(false);
+ [tab_mock_a setUrl:nativeUrl_];
+ [tab_mock_b setUrl:nativeUrl_];
+
+ // Call reload an arbitrary number of times.
+ const int kNumReloads = 4;
+ for (int i = 0; i < kNumReloads; i++) {
+ tab_usage_recorder_->RecordPageLoadStart(tab_mock_a);
+ }
+ tab_usage_recorder_->RecordTabSwitched(tab_mock_a, tab_mock_b);
+ histogram_tester_->ExpectTotalCount(kPageLoadsBeforeEvictedTabSelected, 0);
+}
+
+TEST_F(TabUsageRecorderTest, TestColdStartTabs) {
+ id tab_mock_a = MockTab(false);
+ id tab_mock_b = MockTab(false);
+ id tab_mock_c = MockTab(false);
+ // Set A and B as cold-start evicted tabs. Leave C just evicted.
+ NSMutableArray* cold_start_tabs = [NSMutableArray array];
+ [cold_start_tabs addObject:tab_mock_a];
+ [cold_start_tabs addObject:tab_mock_b];
+ tab_usage_recorder_->InitialRestoredTabs(tab_mock_a, cold_start_tabs);
+
+ // Switch from A (cold start evicted) to B (cold start evicted).
+ tab_usage_recorder_->RecordTabSwitched(tab_mock_a, tab_mock_b);
+ // Switch from B (cold start evicted) to C (evicted).
+ tab_usage_recorder_->RecordTabSwitched(tab_mock_b, tab_mock_c);
+ histogram_tester_->ExpectTotalCount(kSelectedTabHistogramName, 2);
+ histogram_tester_->ExpectBucketCount(
+ kSelectedTabHistogramName, TabUsageRecorder::EVICTED_DUE_TO_COLD_START,
+ 1);
+ histogram_tester_->ExpectBucketCount(kSelectedTabHistogramName,
+ TabUsageRecorder::EVICTED, 1);
+}
+
+TEST_F(TabUsageRecorderTest, TestSwitchedModeTabs) {
+ id tab_mock_a = MockTab(false);
+ id tab_mock_b = MockTab(false);
+ id tab_mock_c = MockTab(false);
+ NSMutableArray* switch_to_incognito_tabs = [NSMutableArray array];
+ [switch_to_incognito_tabs addObject:tab_mock_a];
+ [switch_to_incognito_tabs addObject:tab_mock_b];
+ tab_usage_recorder_->RecordPrimaryTabModelChange(false, nil);
+
+ // Switch from A (incognito evicted) to B (incognito evicted).
+ tab_usage_recorder_->RecordTabSwitched(tab_mock_a, tab_mock_b);
+ // Switch from B (incognito evicted) to C (evicted).
+ tab_usage_recorder_->RecordTabSwitched(tab_mock_b, tab_mock_c);
+ histogram_tester_->ExpectTotalCount(kSelectedTabHistogramName, 2);
+ histogram_tester_->ExpectBucketCount(
+ kSelectedTabHistogramName, TabUsageRecorder::EVICTED_DUE_TO_INCOGNITO, 0);
+ histogram_tester_->ExpectBucketCount(kSelectedTabHistogramName,
+ TabUsageRecorder::EVICTED, 2);
+}
+
+TEST_F(TabUsageRecorderTest, TestEvictedTabReloadTime) {
+ id tab_mock_a = MockTab(true);
+ id tab_mock_b = MockTab(false);
+ tab_usage_recorder_->RecordTabSwitched(tab_mock_a, tab_mock_b);
+ tab_usage_recorder_->RecordPageLoadStart(tab_mock_b);
+ tab_usage_recorder_->RecordPageLoadDone(tab_mock_b, true);
+ histogram_tester_->ExpectTotalCount(kEvictedTabReloadTime, 1);
+}
+
+TEST_F(TabUsageRecorderTest, TestEvictedTabReloadSuccess) {
+ id tab_mock_a = MockTab(true);
+ id tab_mock_b = MockTab(false);
+ tab_usage_recorder_->RecordTabSwitched(tab_mock_a, tab_mock_b);
+ tab_usage_recorder_->RecordPageLoadStart(tab_mock_b);
+ tab_usage_recorder_->RecordPageLoadDone(tab_mock_b, true);
+ histogram_tester_->ExpectUniqueSample(kEvictedTabReloadSuccessRate,
+ TabUsageRecorder::LOAD_SUCCESS, 1);
+}
+
+TEST_F(TabUsageRecorderTest, TestEvictedTabReloadFailure) {
+ id tab_mock_a = MockTab(true);
+ id tab_mock_b = MockTab(false);
+ tab_usage_recorder_->RecordTabSwitched(tab_mock_a, tab_mock_b);
+ tab_usage_recorder_->RecordPageLoadStart(tab_mock_b);
+ tab_usage_recorder_->RecordPageLoadDone(tab_mock_b, false);
+ histogram_tester_->ExpectUniqueSample(kEvictedTabReloadSuccessRate,
+ TabUsageRecorder::LOAD_FAILURE, 1);
+}
+
+TEST_F(TabUsageRecorderTest, TestUserWaitedForEvictedTabLoad) {
+ id tab_mock_a = MockTab(true);
+ id tab_mock_b = MockTab(false);
+ tab_usage_recorder_->RecordTabSwitched(tab_mock_a, tab_mock_b);
+ tab_usage_recorder_->RecordPageLoadStart(tab_mock_b);
+ tab_usage_recorder_->RecordPageLoadDone(tab_mock_b, true);
+ tab_usage_recorder_->RecordTabSwitched(tab_mock_b, tab_mock_a);
+ histogram_tester_->ExpectUniqueSample(kDidUserWaitForEvictedTabReload,
+ TabUsageRecorder::USER_WAITED, 1);
+}
+
+TEST_F(TabUsageRecorderTest, TestUserDidNotWaitForEvictedTabLoad) {
+ id tab_mock_a = MockTab(true);
+ id tab_mock_b = MockTab(false);
+ tab_usage_recorder_->RecordTabSwitched(tab_mock_a, tab_mock_b);
+ tab_usage_recorder_->RecordPageLoadStart(tab_mock_b);
+ tab_usage_recorder_->RecordTabSwitched(tab_mock_b, tab_mock_a);
+ histogram_tester_->ExpectUniqueSample(kDidUserWaitForEvictedTabReload,
+ TabUsageRecorder::USER_DID_NOT_WAIT, 1);
+}
+
+TEST_F(TabUsageRecorderTest, TestUserBackgroundedDuringEvictedTabLoad) {
+ id tab_mock_a = MockTab(true);
+ id tab_mock_b = MockTab(false);
+ tab_usage_recorder_->RecordTabSwitched(tab_mock_a, tab_mock_b);
+ tab_usage_recorder_->RecordPageLoadStart(tab_mock_b);
+ tab_usage_recorder_->AppDidEnterBackground();
+ histogram_tester_->ExpectUniqueSample(kDidUserWaitForEvictedTabReload,
+ TabUsageRecorder::USER_LEFT_CHROME, 1);
+}
+
+TEST_F(TabUsageRecorderTest, TestTimeBetweenRestores) {
+ id tab_mock_a = MockTab(false);
+ id tab_mock_b = MockTab(false);
+ tab_usage_recorder_->RecordTabSwitched(tab_mock_a, tab_mock_b);
+ // Should record the time since launch until this page load begins.
+ tab_usage_recorder_->RecordPageLoadStart(tab_mock_b);
+ tab_usage_recorder_->RecordTabSwitched(tab_mock_b, tab_mock_a);
+ // Should record the time since previous restore until this restore.
+ tab_usage_recorder_->RecordPageLoadStart(tab_mock_a);
+ histogram_tester_->ExpectTotalCount(kTimeBetweenRestores, 2);
+}
+
+TEST_F(TabUsageRecorderTest, TestTimeAfterLastRestore) {
+ id tab_mock_a = MockTab(false);
+ id tab_mock_b = MockTab(false);
+ // Should record time since launch until background.
+ tab_usage_recorder_->AppDidEnterBackground();
+ tab_usage_recorder_->AppWillEnterForeground();
+ tab_usage_recorder_->RecordTabSwitched(tab_mock_a, tab_mock_b);
+ // Should record nothing.
+ tab_usage_recorder_->RecordPageLoadStart(tab_mock_b);
+ histogram_tester_->ExpectTotalCount(kTimeAfterLastRestore, 1);
+}
+
+// Verifies that metrics are recorded correctly when a renderer terminates.
+TEST_F(TabUsageRecorderTest, RendererTerminated) {
+ Tab* terminated_tab = MockTab(false);
+
+ // Set up the delegate to return |kAliveTabsCountAtRenderTermination|.
+ base::scoped_nsobject<MockTabUsageRecorderDelegate> delegate(
+ [[MockTabUsageRecorderDelegate alloc] init]);
+ [delegate setLiveTabsCount:kAliveTabsCountAtRendererTermination];
+ tab_usage_recorder_->SetDelegate(delegate);
+
+ base::TimeTicks now = base::TimeTicks::Now();
+
+ // Add |kExpiredTimesAddedCount| expired timestamps and one recent timestamp
+ // to the termination timestamp list.
+ for (int seconds = kExpiredTimesAddedCount; seconds > 0; seconds--) {
+ int expired_time_delta = kSecondsBeforeRendererTermination + seconds;
+ tab_usage_recorder_->AddTimeToDeque(
+ now - base::TimeDelta::FromSeconds(expired_time_delta));
+ }
+ base::TimeTicks recent_time =
+ now - base::TimeDelta::FromSeconds(kSecondsBeforeRendererTermination / 2);
+ tab_usage_recorder_->AddTimeToDeque(recent_time);
+
+ tab_usage_recorder_->RendererTerminated(terminated_tab, false);
+
+ NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];
+ BOOL saw_memory_warning =
+ [defaults boolForKey:previous_session_info_constants::
+ kDidSeeMemoryWarningShortlyBeforeTerminating];
+ histogram_tester_->ExpectUniqueSample(kRendererTerminationSawMemoryWarning,
+ saw_memory_warning, 1);
+ histogram_tester_->ExpectUniqueSample(kRendererTerminationAliveRenderers,
+ kAliveTabsCountAtRendererTermination,
+ 1);
+ // Tests that the logged count of recently alive renderers is equal to the
+ // live count at termination plus the recent termination and the
+ // renderer terminated just now.
+ histogram_tester_->ExpectUniqueSample(
+ kRendererTerminationRecentlyAliveRenderers,
+ kAliveTabsCountAtRendererTermination + 2, 1);
+}
+
+// Verifies that metrics are recorded correctly when a renderer terminated tab
+// is switched to and reloaded.
+TEST_F(TabUsageRecorderTest, SwitchToRendererTerminatedTab) {
+ id tab_mock_a = MockTab(true);
+ id tab_mock_b = MockTab(false);
+
+ tab_usage_recorder_->RendererTerminated(tab_mock_b, false);
+ tab_usage_recorder_->RecordTabSwitched(tab_mock_a, tab_mock_b);
+
+ histogram_tester_->ExpectUniqueSample(
+ kSelectedTabHistogramName,
+ TabUsageRecorder::EVICTED_DUE_TO_RENDERER_TERMINATION, 1);
+}
+
+} // namespace

Powered by Google App Engine
This is Rietveld 408576698