Chromium Code Reviews| 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. | |
|
calamity
2015/10/28 03:00:25
nit: s/key presses/user input/ and above.
dominickn
2015/10/28 03:28:17
Done.
| |
| 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 NavigateWithDisposition(url2, NEW_FOREGROUND_TAB); | |
| 315 web_contents->WasHidden(); | |
| 316 EXPECT_FALSE(IsTracking(helper.get())); | |
| 317 | |
| 318 // Showing the tab should start tracking again after another delay. | |
| 319 browser()->tab_strip_model()->ActivateTabAt(0, true); | |
| 320 web_contents->WasShown(); | |
| 321 EXPECT_TRUE(input_tracker_timer->IsRunning()); | |
| 322 EXPECT_FALSE(IsTracking(helper.get())); | |
| 323 | |
| 324 // New background tabs should not affect the current tab's input tracking. | |
| 325 NavigateWithDisposition(url2, NEW_BACKGROUND_TAB); | |
| 326 EXPECT_TRUE(input_tracker_timer->IsRunning()); | |
| 327 EXPECT_FALSE(IsTracking(helper.get())); | |
| 328 | |
| 329 input_tracker_timer->Fire(); | |
| 330 EXPECT_FALSE(input_tracker_timer->IsRunning()); | |
| 331 EXPECT_TRUE(IsTracking(helper.get())); | |
| 332 | |
| 333 // New background tabs should not affect the current tab's input tracking. | |
| 334 NavigateWithDisposition(url2, NEW_BACKGROUND_TAB); | |
| 335 EXPECT_FALSE(input_tracker_timer->IsRunning()); | |
| 336 EXPECT_TRUE(IsTracking(helper.get())); | |
| 337 | |
| 338 // Ensure behavior holds when tab is hidden before the initial delay timer | |
| 339 // fires. | |
| 340 NavigateWithDisposition(url2, CURRENT_TAB); | |
| 341 EXPECT_TRUE(input_tracker_timer->IsRunning()); | |
| 342 EXPECT_FALSE(IsTracking(helper.get())); | |
| 343 | |
| 344 NavigateWithDisposition(url2, NEW_FOREGROUND_TAB); | |
| 345 browser()->tab_strip_model()->ActivateTabAt(4, true); | |
| 346 web_contents->WasHidden(); | |
| 347 EXPECT_FALSE(input_tracker_timer->IsRunning()); | |
| 348 EXPECT_FALSE(IsTracking(helper.get())); | |
| 349 | |
| 350 // Showing the tab should start tracking again after another delay. | |
| 351 browser()->tab_strip_model()->ActivateTabAt(0, true); | |
| 352 web_contents->WasShown(); | |
| 353 EXPECT_TRUE(input_tracker_timer->IsRunning()); | |
| 354 EXPECT_FALSE(IsTracking(helper.get())); | |
| 355 | |
| 356 input_tracker_timer->Fire(); | |
| 357 EXPECT_TRUE(IsTracking(helper.get())); | |
|
calamity
2015/10/28 03:00:25
Given that the majority of this test was testing a
dominickn
2015/10/28 03:28:17
Done.
| |
| 358 } | |
| 359 | |
| 360 // Ensure tracking behavior is correct for multiple navigations in a single tab. | |
| 361 TEST_F(SiteEngagementHelperTest, SingleTabNavigation) { | |
| 362 AddTab(browser(), GURL("about:blank")); | |
| 363 GURL url1("https://www.google.com/"); | |
| 364 GURL url2("https://www.example.com/"); | |
| 365 content::WebContents* web_contents = | |
| 366 browser()->tab_strip_model()->GetActiveWebContents(); | |
| 367 | |
| 368 base::MockTimer* input_tracker_timer = new base::MockTimer(true, false); | |
| 369 scoped_ptr<SiteEngagementHelper> helper(CreateHelper(web_contents)); | |
| 370 SetInputTrackerPauseTimer(helper.get(), make_scoped_ptr(input_tracker_timer)); | |
| 371 | |
| 372 // Navigation should start the initial delay timer. | |
| 373 NavigateWithDisposition(url1, CURRENT_TAB); | |
| 374 EXPECT_TRUE(input_tracker_timer->IsRunning()); | |
| 375 EXPECT_FALSE(IsTracking(helper.get())); | |
| 376 | |
| 377 // Navigating before the timer fires should simply reset the timer. | |
| 378 NavigateWithDisposition(url2, CURRENT_TAB); | |
| 379 EXPECT_TRUE(input_tracker_timer->IsRunning()); | |
| 380 EXPECT_FALSE(IsTracking(helper.get())); | |
| 381 | |
| 382 // When the timer fires, callbacks are added. | |
| 383 input_tracker_timer->Fire(); | |
| 384 EXPECT_FALSE(input_tracker_timer->IsRunning()); | |
| 385 EXPECT_TRUE(IsTracking(helper.get())); | |
| 386 | |
| 387 // Navigation should start the initial delay timer again. | |
| 388 NavigateWithDisposition(url1, CURRENT_TAB); | |
| 389 EXPECT_TRUE(input_tracker_timer->IsRunning()); | |
| 390 EXPECT_FALSE(IsTracking(helper.get())); | |
| 391 } | |
| OLD | NEW |