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 key press 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 key presses, 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 key presses 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, WheelEngagementAccumulation) { |
| 130 UserInputAccumulation(blink::WebInputEvent::MouseWheel); |
| 131 } |
| 132 |
| 133 TEST_F(SiteEngagementHelperTest, MixedInputEngagementAccumulation) { |
| 134 AddTab(browser(), GURL("about:blank")); |
| 135 GURL url1("https://www.google.com/"); |
| 136 GURL url2("http://www.google.com/"); |
| 137 content::WebContents* web_contents = |
| 138 browser()->tab_strip_model()->GetActiveWebContents(); |
| 139 |
| 140 scoped_ptr<SiteEngagementHelper> helper(CreateHelper(web_contents)); |
| 141 SiteEngagementService* service = |
| 142 SiteEngagementServiceFactory::GetForProfile(browser()->profile()); |
| 143 DCHECK(service); |
| 144 |
| 145 base::HistogramTester histograms; |
| 146 |
| 147 // Histograms should start off empty. |
| 148 histograms.ExpectTotalCount(SiteEngagementMetrics::kEngagementTypeHistogram, |
| 149 0); |
| 150 |
| 151 NavigateWithDisposition(url1, CURRENT_TAB); |
| 152 StartTracking(helper.get()); |
| 153 |
| 154 EXPECT_DOUBLE_EQ(0.5, service->GetScore(url1)); |
| 155 EXPECT_EQ(0, service->GetScore(url2)); |
| 156 histograms.ExpectTotalCount(SiteEngagementMetrics::kEngagementTypeHistogram, |
| 157 1); |
| 158 histograms.ExpectBucketCount(SiteEngagementMetrics::kEngagementTypeHistogram, |
| 159 SiteEngagementMetrics::ENGAGEMENT_NAVIGATION, 1); |
| 160 |
| 161 HandleUserInputAndRestartTracking(helper.get(), |
| 162 blink::WebInputEvent::RawKeyDown); |
| 163 HandleUserInputAndRestartTracking(helper.get(), |
| 164 blink::WebInputEvent::GestureTapDown); |
| 165 HandleUserInputAndRestartTracking(helper.get(), |
| 166 blink::WebInputEvent::GestureTapDown); |
| 167 HandleUserInputAndRestartTracking(helper.get(), |
| 168 blink::WebInputEvent::MouseWheel); |
| 169 HandleUserInputAndRestartTracking(helper.get(), |
| 170 blink::WebInputEvent::MouseDown); |
| 171 |
| 172 EXPECT_DOUBLE_EQ(0.75, service->GetScore(url1)); |
| 173 EXPECT_EQ(0, service->GetScore(url2)); |
| 174 histograms.ExpectTotalCount(SiteEngagementMetrics::kEngagementTypeHistogram, |
| 175 6); |
| 176 histograms.ExpectBucketCount(SiteEngagementMetrics::kEngagementTypeHistogram, |
| 177 SiteEngagementMetrics::ENGAGEMENT_NAVIGATION, 1); |
| 178 histograms.ExpectBucketCount(SiteEngagementMetrics::kEngagementTypeHistogram, |
| 179 SiteEngagementMetrics::ENGAGEMENT_KEYPRESS, 1); |
| 180 histograms.ExpectBucketCount(SiteEngagementMetrics::kEngagementTypeHistogram, |
| 181 SiteEngagementMetrics::ENGAGEMENT_MOUSE, 1); |
| 182 histograms.ExpectBucketCount(SiteEngagementMetrics::kEngagementTypeHistogram, |
| 183 SiteEngagementMetrics::ENGAGEMENT_WHEEL, 1); |
| 184 histograms.ExpectBucketCount(SiteEngagementMetrics::kEngagementTypeHistogram, |
| 185 SiteEngagementMetrics::ENGAGEMENT_GESTURE, 2); |
| 186 |
| 187 HandleUserInputAndRestartTracking(helper.get(), |
| 188 blink::WebInputEvent::MouseDown); |
| 189 HandleUserInputAndRestartTracking(helper.get(), |
| 190 blink::WebInputEvent::MouseDown); |
| 191 HandleUserInputAndRestartTracking(helper.get(), |
| 192 blink::WebInputEvent::MouseWheel); |
| 193 |
| 194 EXPECT_DOUBLE_EQ(0.9, service->GetScore(url1)); |
| 195 EXPECT_EQ(0, service->GetScore(url2)); |
| 196 histograms.ExpectTotalCount(SiteEngagementMetrics::kEngagementTypeHistogram, |
| 197 9); |
| 198 histograms.ExpectBucketCount(SiteEngagementMetrics::kEngagementTypeHistogram, |
| 199 SiteEngagementMetrics::ENGAGEMENT_MOUSE, 3); |
| 200 histograms.ExpectBucketCount(SiteEngagementMetrics::kEngagementTypeHistogram, |
| 201 SiteEngagementMetrics::ENGAGEMENT_WHEEL, 2); |
| 202 |
| 203 NavigateWithDisposition(url2, CURRENT_TAB); |
| 204 StartTracking(helper.get()); |
| 205 |
| 206 EXPECT_DOUBLE_EQ(0.9, service->GetScore(url1)); |
| 207 EXPECT_DOUBLE_EQ(0.5, service->GetScore(url2)); |
| 208 EXPECT_DOUBLE_EQ(1.4, service->GetTotalEngagementPoints()); |
| 209 |
| 210 HandleUserInputAndRestartTracking(helper.get(), |
| 211 blink::WebInputEvent::GestureTapDown); |
| 212 HandleUserInputAndRestartTracking(helper.get(), |
| 213 blink::WebInputEvent::RawKeyDown); |
| 214 |
| 215 EXPECT_DOUBLE_EQ(0.9, service->GetScore(url1)); |
| 216 EXPECT_DOUBLE_EQ(0.6, service->GetScore(url2)); |
| 217 EXPECT_DOUBLE_EQ(1.5, service->GetTotalEngagementPoints()); |
| 218 histograms.ExpectTotalCount(SiteEngagementMetrics::kEngagementTypeHistogram, |
| 219 12); |
| 220 histograms.ExpectBucketCount(SiteEngagementMetrics::kEngagementTypeHistogram, |
| 221 SiteEngagementMetrics::ENGAGEMENT_NAVIGATION, 2); |
| 222 histograms.ExpectBucketCount(SiteEngagementMetrics::kEngagementTypeHistogram, |
| 223 SiteEngagementMetrics::ENGAGEMENT_KEYPRESS, 2); |
| 224 histograms.ExpectBucketCount(SiteEngagementMetrics::kEngagementTypeHistogram, |
| 225 SiteEngagementMetrics::ENGAGEMENT_GESTURE, 3); |
| 226 } |
| 227 |
| 228 TEST_F(SiteEngagementHelperTest, CheckTimerAndCallbacks) { |
| 229 AddTab(browser(), GURL("about:blank")); |
| 230 GURL url1("https://www.google.com/"); |
| 231 GURL url2("http://www.google.com/"); |
| 232 content::WebContents* web_contents = |
| 233 browser()->tab_strip_model()->GetActiveWebContents(); |
| 234 |
| 235 base::MockTimer* input_tracker_timer = new base::MockTimer(true, false); |
| 236 scoped_ptr<SiteEngagementHelper> helper(CreateHelper(web_contents)); |
| 237 SetInputTrackerPauseTimer(helper.get(), make_scoped_ptr(input_tracker_timer)); |
| 238 |
| 239 SiteEngagementService* service = |
| 240 SiteEngagementServiceFactory::GetForProfile(browser()->profile()); |
| 241 DCHECK(service); |
| 242 |
| 243 NavigateWithDisposition(url1, CURRENT_TAB); |
| 244 EXPECT_DOUBLE_EQ(0.5, service->GetScore(url1)); |
| 245 EXPECT_EQ(0, service->GetScore(url2)); |
| 246 |
| 247 // Timer should be running for navigation delay. |
| 248 EXPECT_TRUE(input_tracker_timer->IsRunning()); |
| 249 EXPECT_FALSE(IsTracking(helper.get())); |
| 250 input_tracker_timer->Fire(); |
| 251 |
| 252 // Timer should start running again after input. |
| 253 EXPECT_FALSE(input_tracker_timer->IsRunning()); |
| 254 EXPECT_TRUE(IsTracking(helper.get())); |
| 255 HandleUserInput(helper.get(), blink::WebInputEvent::RawKeyDown); |
| 256 EXPECT_TRUE(input_tracker_timer->IsRunning()); |
| 257 EXPECT_FALSE(IsTracking(helper.get())); |
| 258 |
| 259 EXPECT_DOUBLE_EQ(0.55, service->GetScore(url1)); |
| 260 EXPECT_EQ(0, service->GetScore(url2)); |
| 261 |
| 262 input_tracker_timer->Fire(); |
| 263 EXPECT_FALSE(input_tracker_timer->IsRunning()); |
| 264 EXPECT_TRUE(IsTracking(helper.get())); |
| 265 |
| 266 // Timer should start running again after input. |
| 267 HandleUserInput(helper.get(), blink::WebInputEvent::MouseWheel); |
| 268 EXPECT_TRUE(input_tracker_timer->IsRunning()); |
| 269 EXPECT_FALSE(IsTracking(helper.get())); |
| 270 |
| 271 EXPECT_DOUBLE_EQ(0.6, service->GetScore(url1)); |
| 272 EXPECT_EQ(0, service->GetScore(url2)); |
| 273 |
| 274 input_tracker_timer->Fire(); |
| 275 EXPECT_FALSE(input_tracker_timer->IsRunning()); |
| 276 EXPECT_TRUE(IsTracking(helper.get())); |
| 277 |
| 278 // Timer should be running for navigation delay. |
| 279 NavigateWithDisposition(url2, CURRENT_TAB); |
| 280 EXPECT_TRUE(input_tracker_timer->IsRunning()); |
| 281 EXPECT_FALSE(IsTracking(helper.get())); |
| 282 |
| 283 EXPECT_DOUBLE_EQ(0.6, service->GetScore(url1)); |
| 284 EXPECT_DOUBLE_EQ(0.5, service->GetScore(url2)); |
| 285 |
| 286 input_tracker_timer->Fire(); |
| 287 EXPECT_FALSE(input_tracker_timer->IsRunning()); |
| 288 EXPECT_TRUE(IsTracking(helper.get())); |
| 289 |
| 290 HandleUserInput(helper.get(), blink::WebInputEvent::MouseDown); |
| 291 EXPECT_TRUE(input_tracker_timer->IsRunning()); |
| 292 EXPECT_FALSE(IsTracking(helper.get())); |
| 293 |
| 294 EXPECT_DOUBLE_EQ(0.6, service->GetScore(url1)); |
| 295 EXPECT_DOUBLE_EQ(0.55, service->GetScore(url2)); |
| 296 EXPECT_DOUBLE_EQ(1.15, service->GetTotalEngagementPoints()); |
| 297 } |
| 298 |
| 299 // Ensure that navigation does not trigger input tracking until after a delay. |
| 300 // We must manually call WasShown/WasHidden as they are not triggered |
| 301 // automatically in this test environment. |
| 302 TEST_F(SiteEngagementHelperTest, ShowAndHide) { |
| 303 AddTab(browser(), GURL("about:blank")); |
| 304 GURL url1("https://www.google.com/"); |
| 305 GURL url2("http://www.google.com/"); |
| 306 content::WebContents* web_contents = |
| 307 browser()->tab_strip_model()->GetActiveWebContents(); |
| 308 |
| 309 base::MockTimer* input_tracker_timer = new base::MockTimer(true, false); |
| 310 scoped_ptr<SiteEngagementHelper> helper(CreateHelper(web_contents)); |
| 311 SetInputTrackerPauseTimer(helper.get(), make_scoped_ptr(input_tracker_timer)); |
| 312 |
| 313 NavigateWithDisposition(url1, CURRENT_TAB); |
| 314 input_tracker_timer->Fire(); |
| 315 |
| 316 EXPECT_FALSE(input_tracker_timer->IsRunning()); |
| 317 EXPECT_TRUE(IsTracking(helper.get())); |
| 318 |
| 319 // Hiding the tab should stop input tracking. |
| 320 NavigateWithDisposition(url2, NEW_FOREGROUND_TAB); |
| 321 web_contents->WasHidden(); |
| 322 EXPECT_FALSE(IsTracking(helper.get())); |
| 323 |
| 324 // Showing the tab should start tracking again after another delay. |
| 325 browser()->tab_strip_model()->ActivateTabAt(0, true); |
| 326 web_contents->WasShown(); |
| 327 EXPECT_TRUE(input_tracker_timer->IsRunning()); |
| 328 EXPECT_FALSE(IsTracking(helper.get())); |
| 329 |
| 330 // New background tabs should not affect the current tab's input tracking. |
| 331 NavigateWithDisposition(url2, NEW_BACKGROUND_TAB); |
| 332 EXPECT_TRUE(input_tracker_timer->IsRunning()); |
| 333 EXPECT_FALSE(IsTracking(helper.get())); |
| 334 |
| 335 input_tracker_timer->Fire(); |
| 336 EXPECT_FALSE(input_tracker_timer->IsRunning()); |
| 337 EXPECT_TRUE(IsTracking(helper.get())); |
| 338 |
| 339 // New background tabs should not affect the current tab's input tracking. |
| 340 NavigateWithDisposition(url2, NEW_BACKGROUND_TAB); |
| 341 EXPECT_FALSE(input_tracker_timer->IsRunning()); |
| 342 EXPECT_TRUE(IsTracking(helper.get())); |
| 343 |
| 344 // Ensure behavior holds when tab is hidden before the initial delay timer |
| 345 // fires. |
| 346 NavigateWithDisposition(url2, CURRENT_TAB); |
| 347 EXPECT_TRUE(input_tracker_timer->IsRunning()); |
| 348 EXPECT_FALSE(IsTracking(helper.get())); |
| 349 |
| 350 NavigateWithDisposition(url2, NEW_FOREGROUND_TAB); |
| 351 browser()->tab_strip_model()->ActivateTabAt(4, true); |
| 352 web_contents->WasHidden(); |
| 353 EXPECT_FALSE(input_tracker_timer->IsRunning()); |
| 354 EXPECT_FALSE(IsTracking(helper.get())); |
| 355 |
| 356 // Showing the tab should start tracking again after another delay. |
| 357 browser()->tab_strip_model()->ActivateTabAt(0, true); |
| 358 web_contents->WasShown(); |
| 359 EXPECT_TRUE(input_tracker_timer->IsRunning()); |
| 360 EXPECT_FALSE(IsTracking(helper.get())); |
| 361 |
| 362 input_tracker_timer->Fire(); |
| 363 EXPECT_TRUE(IsTracking(helper.get())); |
| 364 } |
| 365 |
| 366 // Ensure tracking behavior is correct for multiple navigations in a single tab. |
| 367 TEST_F(SiteEngagementHelperTest, SingleTabNavigation) { |
| 368 AddTab(browser(), GURL("about:blank")); |
| 369 GURL url1("https://www.google.com/"); |
| 370 GURL url2("https://www.example.com/"); |
| 371 content::WebContents* web_contents = |
| 372 browser()->tab_strip_model()->GetActiveWebContents(); |
| 373 |
| 374 base::MockTimer* input_tracker_timer = new base::MockTimer(true, false); |
| 375 scoped_ptr<SiteEngagementHelper> helper(CreateHelper(web_contents)); |
| 376 SetInputTrackerPauseTimer(helper.get(), make_scoped_ptr(input_tracker_timer)); |
| 377 |
| 378 // Navigation should start the initial delay timer. |
| 379 NavigateWithDisposition(url1, CURRENT_TAB); |
| 380 EXPECT_TRUE(input_tracker_timer->IsRunning()); |
| 381 EXPECT_FALSE(IsTracking(helper.get())); |
| 382 |
| 383 // Navigating before the timer fires should simply reset the timer. |
| 384 NavigateWithDisposition(url2, CURRENT_TAB); |
| 385 EXPECT_TRUE(input_tracker_timer->IsRunning()); |
| 386 EXPECT_FALSE(IsTracking(helper.get())); |
| 387 |
| 388 // When the timer fires, callbacks are added. |
| 389 input_tracker_timer->Fire(); |
| 390 EXPECT_FALSE(input_tracker_timer->IsRunning()); |
| 391 EXPECT_TRUE(IsTracking(helper.get())); |
| 392 |
| 393 // Navigation should start the initial delay timer again. |
| 394 NavigateWithDisposition(url1, CURRENT_TAB); |
| 395 EXPECT_TRUE(input_tracker_timer->IsRunning()); |
| 396 EXPECT_FALSE(IsTracking(helper.get())); |
| 397 } |
OLD | NEW |