OLD | NEW |
(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 "base/command_line.h" |
| 6 #include "base/test/histogram_tester.h" |
| 7 #include "base/timer/mock_timer.h" |
| 8 #include "base/values.h" |
| 9 #include "chrome/browser/engagement/site_engagement_helper.h" |
| 10 #include "chrome/browser/engagement/site_engagement_service.h" |
| 11 #include "chrome/browser/engagement/site_engagement_service_factory.h" |
| 12 #include "chrome/browser/ui/browser.h" |
| 13 #include "chrome/browser/ui/tabs/tab_strip_model.h" |
| 14 #include "chrome/common/chrome_switches.h" |
| 15 #include "chrome/test/base/browser_with_test_window_test.h" |
| 16 #include "content/public/browser/page_navigator.h" |
| 17 #include "testing/gtest/include/gtest/gtest.h" |
| 18 |
| 19 class SiteEngagementHelperTest : public BrowserWithTestWindowTest { |
| 20 public: |
| 21 // Create a SiteEngagementHelper. Called here as friend class methods cannot |
| 22 // be called in tests. |
| 23 scoped_ptr<SiteEngagementHelper> CreateHelper( |
| 24 content::WebContents* web_contents) { |
| 25 scoped_ptr<SiteEngagementHelper> helper( |
| 26 new SiteEngagementHelper(web_contents)); |
| 27 DCHECK(helper.get()); |
| 28 |
| 29 return helper.Pass(); |
| 30 } |
| 31 |
| 32 void StartTracking(SiteEngagementHelper* helper) { |
| 33 helper->input_tracker_.StartTracking(); |
| 34 } |
| 35 |
| 36 // Simulate a user interaction event and handle it. |
| 37 void HandleUserInput(SiteEngagementHelper* helper, |
| 38 blink::WebInputEvent::Type type) { |
| 39 helper->input_tracker_.DidGetUserInteraction(type); |
| 40 } |
| 41 |
| 42 // Simulate a user interaction event and handle it. Reactivates tracking |
| 43 // immediately. |
| 44 void HandleUserInputAndRestartTracking(SiteEngagementHelper* helper, |
| 45 blink::WebInputEvent::Type type) { |
| 46 helper->input_tracker_.DidGetUserInteraction(type); |
| 47 helper->input_tracker_.StartTracking(); |
| 48 } |
| 49 |
| 50 // Set a pause timer on the input tracker for test purposes. |
| 51 void SetInputTrackerPauseTimer(SiteEngagementHelper* helper, |
| 52 scoped_ptr<base::Timer> timer) { |
| 53 helper->input_tracker_.SetPauseTimerForTesting(timer.Pass()); |
| 54 } |
| 55 |
| 56 bool IsTracking(SiteEngagementHelper* helper) { |
| 57 return helper->input_tracker_.is_tracking(); |
| 58 } |
| 59 |
| 60 void NavigateWithDisposition(GURL& url, WindowOpenDisposition disposition) { |
| 61 content::NavigationController* controller = |
| 62 &browser()->tab_strip_model()->GetActiveWebContents()->GetController(); |
| 63 browser()->OpenURL( |
| 64 content::OpenURLParams(url, content::Referrer(), disposition, |
| 65 ui::PAGE_TRANSITION_TYPED, false)); |
| 66 CommitPendingLoad(controller); |
| 67 } |
| 68 |
| 69 void UserInputAccumulation(const blink::WebInputEvent::Type type) { |
| 70 AddTab(browser(), GURL("about:blank")); |
| 71 GURL url1("https://www.google.com/"); |
| 72 GURL url2("http://www.google.com/"); |
| 73 content::WebContents* web_contents = |
| 74 browser()->tab_strip_model()->GetActiveWebContents(); |
| 75 |
| 76 scoped_ptr<SiteEngagementHelper> helper(CreateHelper(web_contents)); |
| 77 SiteEngagementService* service = |
| 78 SiteEngagementServiceFactory::GetForProfile(browser()->profile()); |
| 79 DCHECK(service); |
| 80 |
| 81 // Check that navigation triggers engagement. |
| 82 NavigateWithDisposition(url1, CURRENT_TAB); |
| 83 StartTracking(helper.get()); |
| 84 |
| 85 EXPECT_DOUBLE_EQ(0.5, service->GetScore(url1)); |
| 86 EXPECT_EQ(0, service->GetScore(url2)); |
| 87 |
| 88 // Simulate a user input trigger and ensure it is treated correctly. |
| 89 HandleUserInputAndRestartTracking(helper.get(), type); |
| 90 |
| 91 EXPECT_DOUBLE_EQ(0.55, service->GetScore(url1)); |
| 92 EXPECT_EQ(0, service->GetScore(url2)); |
| 93 |
| 94 // Simulate three inputs , and ensure they are treated correctly. |
| 95 HandleUserInputAndRestartTracking(helper.get(), type); |
| 96 HandleUserInputAndRestartTracking(helper.get(), type); |
| 97 HandleUserInputAndRestartTracking(helper.get(), type); |
| 98 |
| 99 EXPECT_DOUBLE_EQ(0.7, service->GetScore(url1)); |
| 100 EXPECT_EQ(0, service->GetScore(url2)); |
| 101 |
| 102 // Simulate inputs for a different link. |
| 103 NavigateWithDisposition(url2, CURRENT_TAB); |
| 104 StartTracking(helper.get()); |
| 105 |
| 106 EXPECT_DOUBLE_EQ(0.7, service->GetScore(url1)); |
| 107 EXPECT_DOUBLE_EQ(0.5, service->GetScore(url2)); |
| 108 EXPECT_DOUBLE_EQ(1.2, service->GetTotalEngagementPoints()); |
| 109 |
| 110 HandleUserInputAndRestartTracking(helper.get(), type); |
| 111 EXPECT_DOUBLE_EQ(0.7, service->GetScore(url1)); |
| 112 EXPECT_DOUBLE_EQ(0.55, service->GetScore(url2)); |
| 113 EXPECT_DOUBLE_EQ(1.25, service->GetTotalEngagementPoints()); |
| 114 } |
| 115 }; |
| 116 |
| 117 TEST_F(SiteEngagementHelperTest, KeyPressEngagementAccumulation) { |
| 118 UserInputAccumulation(blink::WebInputEvent::RawKeyDown); |
| 119 } |
| 120 |
| 121 TEST_F(SiteEngagementHelperTest, MouseEventEngagementAccumulation) { |
| 122 UserInputAccumulation(blink::WebInputEvent::MouseDown); |
| 123 } |
| 124 |
| 125 TEST_F(SiteEngagementHelperTest, GestureEngagementAccumulation) { |
| 126 UserInputAccumulation(blink::WebInputEvent::GestureTapDown); |
| 127 } |
| 128 |
| 129 TEST_F(SiteEngagementHelperTest, MixedInputEngagementAccumulation) { |
| 130 AddTab(browser(), GURL("about:blank")); |
| 131 GURL url1("https://www.google.com/"); |
| 132 GURL url2("http://www.google.com/"); |
| 133 content::WebContents* web_contents = |
| 134 browser()->tab_strip_model()->GetActiveWebContents(); |
| 135 |
| 136 scoped_ptr<SiteEngagementHelper> helper(CreateHelper(web_contents)); |
| 137 SiteEngagementService* service = |
| 138 SiteEngagementServiceFactory::GetForProfile(browser()->profile()); |
| 139 DCHECK(service); |
| 140 |
| 141 base::HistogramTester histograms; |
| 142 |
| 143 // Histograms should start off empty. |
| 144 histograms.ExpectTotalCount(SiteEngagementMetrics::kEngagementTypeHistogram, |
| 145 0); |
| 146 |
| 147 NavigateWithDisposition(url1, CURRENT_TAB); |
| 148 StartTracking(helper.get()); |
| 149 |
| 150 EXPECT_DOUBLE_EQ(0.5, service->GetScore(url1)); |
| 151 EXPECT_EQ(0, service->GetScore(url2)); |
| 152 histograms.ExpectTotalCount(SiteEngagementMetrics::kEngagementTypeHistogram, |
| 153 1); |
| 154 histograms.ExpectBucketCount(SiteEngagementMetrics::kEngagementTypeHistogram, |
| 155 SiteEngagementMetrics::ENGAGEMENT_NAVIGATION, 1); |
| 156 |
| 157 HandleUserInputAndRestartTracking(helper.get(), |
| 158 blink::WebInputEvent::RawKeyDown); |
| 159 HandleUserInputAndRestartTracking(helper.get(), |
| 160 blink::WebInputEvent::GestureTapDown); |
| 161 HandleUserInputAndRestartTracking(helper.get(), |
| 162 blink::WebInputEvent::GestureTapDown); |
| 163 HandleUserInputAndRestartTracking(helper.get(), |
| 164 blink::WebInputEvent::RawKeyDown); |
| 165 HandleUserInputAndRestartTracking(helper.get(), |
| 166 blink::WebInputEvent::MouseDown); |
| 167 |
| 168 EXPECT_DOUBLE_EQ(0.75, service->GetScore(url1)); |
| 169 EXPECT_EQ(0, service->GetScore(url2)); |
| 170 histograms.ExpectTotalCount(SiteEngagementMetrics::kEngagementTypeHistogram, |
| 171 6); |
| 172 histograms.ExpectBucketCount(SiteEngagementMetrics::kEngagementTypeHistogram, |
| 173 SiteEngagementMetrics::ENGAGEMENT_NAVIGATION, 1); |
| 174 histograms.ExpectBucketCount(SiteEngagementMetrics::kEngagementTypeHistogram, |
| 175 SiteEngagementMetrics::ENGAGEMENT_KEYPRESS, 2); |
| 176 histograms.ExpectBucketCount(SiteEngagementMetrics::kEngagementTypeHistogram, |
| 177 SiteEngagementMetrics::ENGAGEMENT_MOUSE, 1); |
| 178 histograms.ExpectBucketCount(SiteEngagementMetrics::kEngagementTypeHistogram, |
| 179 SiteEngagementMetrics::ENGAGEMENT_GESTURE, 2); |
| 180 |
| 181 HandleUserInputAndRestartTracking(helper.get(), |
| 182 blink::WebInputEvent::MouseDown); |
| 183 HandleUserInputAndRestartTracking(helper.get(), |
| 184 blink::WebInputEvent::MouseDown); |
| 185 HandleUserInputAndRestartTracking(helper.get(), |
| 186 blink::WebInputEvent::GestureTapDown); |
| 187 |
| 188 EXPECT_DOUBLE_EQ(0.9, service->GetScore(url1)); |
| 189 EXPECT_EQ(0, service->GetScore(url2)); |
| 190 histograms.ExpectTotalCount(SiteEngagementMetrics::kEngagementTypeHistogram, |
| 191 9); |
| 192 histograms.ExpectBucketCount(SiteEngagementMetrics::kEngagementTypeHistogram, |
| 193 SiteEngagementMetrics::ENGAGEMENT_MOUSE, 3); |
| 194 histograms.ExpectBucketCount(SiteEngagementMetrics::kEngagementTypeHistogram, |
| 195 SiteEngagementMetrics::ENGAGEMENT_GESTURE, 3); |
| 196 |
| 197 NavigateWithDisposition(url2, CURRENT_TAB); |
| 198 StartTracking(helper.get()); |
| 199 |
| 200 EXPECT_DOUBLE_EQ(0.9, service->GetScore(url1)); |
| 201 EXPECT_DOUBLE_EQ(0.5, service->GetScore(url2)); |
| 202 EXPECT_DOUBLE_EQ(1.4, service->GetTotalEngagementPoints()); |
| 203 |
| 204 HandleUserInputAndRestartTracking(helper.get(), |
| 205 blink::WebInputEvent::GestureTapDown); |
| 206 HandleUserInputAndRestartTracking(helper.get(), |
| 207 blink::WebInputEvent::RawKeyDown); |
| 208 |
| 209 EXPECT_DOUBLE_EQ(0.9, service->GetScore(url1)); |
| 210 EXPECT_DOUBLE_EQ(0.6, service->GetScore(url2)); |
| 211 EXPECT_DOUBLE_EQ(1.5, service->GetTotalEngagementPoints()); |
| 212 histograms.ExpectTotalCount(SiteEngagementMetrics::kEngagementTypeHistogram, |
| 213 12); |
| 214 histograms.ExpectBucketCount(SiteEngagementMetrics::kEngagementTypeHistogram, |
| 215 SiteEngagementMetrics::ENGAGEMENT_NAVIGATION, 2); |
| 216 histograms.ExpectBucketCount(SiteEngagementMetrics::kEngagementTypeHistogram, |
| 217 SiteEngagementMetrics::ENGAGEMENT_KEYPRESS, 3); |
| 218 histograms.ExpectBucketCount(SiteEngagementMetrics::kEngagementTypeHistogram, |
| 219 SiteEngagementMetrics::ENGAGEMENT_GESTURE, 4); |
| 220 } |
| 221 |
| 222 TEST_F(SiteEngagementHelperTest, CheckTimerAndCallbacks) { |
| 223 AddTab(browser(), GURL("about:blank")); |
| 224 GURL url1("https://www.google.com/"); |
| 225 GURL url2("http://www.google.com/"); |
| 226 content::WebContents* web_contents = |
| 227 browser()->tab_strip_model()->GetActiveWebContents(); |
| 228 |
| 229 base::MockTimer* input_tracker_timer = new base::MockTimer(true, false); |
| 230 scoped_ptr<SiteEngagementHelper> helper(CreateHelper(web_contents)); |
| 231 SetInputTrackerPauseTimer(helper.get(), make_scoped_ptr(input_tracker_timer)); |
| 232 |
| 233 SiteEngagementService* service = |
| 234 SiteEngagementServiceFactory::GetForProfile(browser()->profile()); |
| 235 DCHECK(service); |
| 236 |
| 237 NavigateWithDisposition(url1, CURRENT_TAB); |
| 238 EXPECT_DOUBLE_EQ(0.5, service->GetScore(url1)); |
| 239 EXPECT_EQ(0, service->GetScore(url2)); |
| 240 |
| 241 // Timer should be running for navigation delay. |
| 242 EXPECT_TRUE(input_tracker_timer->IsRunning()); |
| 243 EXPECT_FALSE(IsTracking(helper.get())); |
| 244 input_tracker_timer->Fire(); |
| 245 |
| 246 // Timer should start running again after input. |
| 247 EXPECT_FALSE(input_tracker_timer->IsRunning()); |
| 248 EXPECT_TRUE(IsTracking(helper.get())); |
| 249 HandleUserInput(helper.get(), blink::WebInputEvent::RawKeyDown); |
| 250 EXPECT_TRUE(input_tracker_timer->IsRunning()); |
| 251 EXPECT_FALSE(IsTracking(helper.get())); |
| 252 |
| 253 EXPECT_DOUBLE_EQ(0.55, service->GetScore(url1)); |
| 254 EXPECT_EQ(0, service->GetScore(url2)); |
| 255 |
| 256 input_tracker_timer->Fire(); |
| 257 EXPECT_FALSE(input_tracker_timer->IsRunning()); |
| 258 EXPECT_TRUE(IsTracking(helper.get())); |
| 259 |
| 260 // Timer should start running again after input. |
| 261 HandleUserInput(helper.get(), blink::WebInputEvent::GestureTapDown); |
| 262 EXPECT_TRUE(input_tracker_timer->IsRunning()); |
| 263 EXPECT_FALSE(IsTracking(helper.get())); |
| 264 |
| 265 EXPECT_DOUBLE_EQ(0.6, service->GetScore(url1)); |
| 266 EXPECT_EQ(0, service->GetScore(url2)); |
| 267 |
| 268 input_tracker_timer->Fire(); |
| 269 EXPECT_FALSE(input_tracker_timer->IsRunning()); |
| 270 EXPECT_TRUE(IsTracking(helper.get())); |
| 271 |
| 272 // Timer should be running for navigation delay. |
| 273 NavigateWithDisposition(url2, CURRENT_TAB); |
| 274 EXPECT_TRUE(input_tracker_timer->IsRunning()); |
| 275 EXPECT_FALSE(IsTracking(helper.get())); |
| 276 |
| 277 EXPECT_DOUBLE_EQ(0.6, service->GetScore(url1)); |
| 278 EXPECT_DOUBLE_EQ(0.5, service->GetScore(url2)); |
| 279 |
| 280 input_tracker_timer->Fire(); |
| 281 EXPECT_FALSE(input_tracker_timer->IsRunning()); |
| 282 EXPECT_TRUE(IsTracking(helper.get())); |
| 283 |
| 284 HandleUserInput(helper.get(), blink::WebInputEvent::MouseDown); |
| 285 EXPECT_TRUE(input_tracker_timer->IsRunning()); |
| 286 EXPECT_FALSE(IsTracking(helper.get())); |
| 287 |
| 288 EXPECT_DOUBLE_EQ(0.6, service->GetScore(url1)); |
| 289 EXPECT_DOUBLE_EQ(0.55, service->GetScore(url2)); |
| 290 EXPECT_DOUBLE_EQ(1.15, service->GetTotalEngagementPoints()); |
| 291 } |
| 292 |
| 293 // Ensure that navigation does not trigger input tracking until after a delay. |
| 294 // We must manually call WasShown/WasHidden as they are not triggered |
| 295 // automatically in this test environment. |
| 296 TEST_F(SiteEngagementHelperTest, ShowAndHide) { |
| 297 AddTab(browser(), GURL("about:blank")); |
| 298 GURL url1("https://www.google.com/"); |
| 299 GURL url2("http://www.google.com/"); |
| 300 content::WebContents* web_contents = |
| 301 browser()->tab_strip_model()->GetActiveWebContents(); |
| 302 |
| 303 base::MockTimer* input_tracker_timer = new base::MockTimer(true, false); |
| 304 scoped_ptr<SiteEngagementHelper> helper(CreateHelper(web_contents)); |
| 305 SetInputTrackerPauseTimer(helper.get(), make_scoped_ptr(input_tracker_timer)); |
| 306 |
| 307 NavigateWithDisposition(url1, CURRENT_TAB); |
| 308 input_tracker_timer->Fire(); |
| 309 |
| 310 EXPECT_FALSE(input_tracker_timer->IsRunning()); |
| 311 EXPECT_TRUE(IsTracking(helper.get())); |
| 312 |
| 313 // Hiding the tab should stop input tracking. |
| 314 web_contents->WasHidden(); |
| 315 EXPECT_FALSE(input_tracker_timer->IsRunning()); |
| 316 EXPECT_FALSE(IsTracking(helper.get())); |
| 317 |
| 318 // Showing the tab should start tracking again after another delay. |
| 319 web_contents->WasShown(); |
| 320 EXPECT_TRUE(input_tracker_timer->IsRunning()); |
| 321 EXPECT_FALSE(IsTracking(helper.get())); |
| 322 |
| 323 input_tracker_timer->Fire(); |
| 324 EXPECT_FALSE(input_tracker_timer->IsRunning()); |
| 325 EXPECT_TRUE(IsTracking(helper.get())); |
| 326 } |
| 327 |
| 328 // Ensure tracking behavior is correct for multiple navigations in a single tab. |
| 329 TEST_F(SiteEngagementHelperTest, SingleTabNavigation) { |
| 330 AddTab(browser(), GURL("about:blank")); |
| 331 GURL url1("https://www.google.com/"); |
| 332 GURL url2("https://www.example.com/"); |
| 333 content::WebContents* web_contents = |
| 334 browser()->tab_strip_model()->GetActiveWebContents(); |
| 335 |
| 336 base::MockTimer* input_tracker_timer = new base::MockTimer(true, false); |
| 337 scoped_ptr<SiteEngagementHelper> helper(CreateHelper(web_contents)); |
| 338 SetInputTrackerPauseTimer(helper.get(), make_scoped_ptr(input_tracker_timer)); |
| 339 |
| 340 // Navigation should start the initial delay timer. |
| 341 NavigateWithDisposition(url1, CURRENT_TAB); |
| 342 EXPECT_TRUE(input_tracker_timer->IsRunning()); |
| 343 EXPECT_FALSE(IsTracking(helper.get())); |
| 344 |
| 345 // Navigating before the timer fires should simply reset the timer. |
| 346 NavigateWithDisposition(url2, CURRENT_TAB); |
| 347 EXPECT_TRUE(input_tracker_timer->IsRunning()); |
| 348 EXPECT_FALSE(IsTracking(helper.get())); |
| 349 |
| 350 // When the timer fires, callbacks are added. |
| 351 input_tracker_timer->Fire(); |
| 352 EXPECT_FALSE(input_tracker_timer->IsRunning()); |
| 353 EXPECT_TRUE(IsTracking(helper.get())); |
| 354 |
| 355 // Navigation should start the initial delay timer again. |
| 356 NavigateWithDisposition(url1, CURRENT_TAB); |
| 357 EXPECT_TRUE(input_tracker_timer->IsRunning()); |
| 358 EXPECT_FALSE(IsTracking(helper.get())); |
| 359 } |
OLD | NEW |