Index: tools/perf/page_sets/infinite_scroll_cases.py |
diff --git a/tools/perf/page_sets/infinite_scroll_cases.py b/tools/perf/page_sets/infinite_scroll_cases.py |
index 7930a6e70a2cc9078b1f9fa0ba57692faf46991e..25221f0850cf82d3004812ab3df5d04d0571a000 100644 |
--- a/tools/perf/page_sets/infinite_scroll_cases.py |
+++ b/tools/perf/page_sets/infinite_scroll_cases.py |
@@ -1,80 +1,157 @@ |
-# Copyright 2015 The Chromium Authors. All rights reserved. |
+# Copyright 2017 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. |
-from telemetry.page import page as page_module |
+ |
+import sys |
+ |
+from page_sets.login_helpers import facebook_login |
+from page_sets.system_health import platforms |
+from telemetry.core import discover |
+from telemetry.page import page |
from telemetry.page import shared_page_state |
from telemetry import story |
-TIME_TO_WAIT_BEFORE_STARTING_IN_SECONDS = 5 |
-SCROLL_TIMEOUT_IN_SECONDS = 120 |
+class _InfiniteScrollStory(page.Page): |
+ """ Base class for infinite scroll stories.""" |
-# TODO(ulan): Remove this once crbug.com/541508 is fixed. |
-STARTUP_SCRIPT = ''' |
- window.WebSocket = undefined; |
- window.Worker = undefined; |
- window.performance = undefined;''' |
+ NAME = NotImplemented |
+ URL = NotImplemented |
+ SUPPORTED_PLATFORMS = platforms.ALL_PLATFORMS |
+ SCROLL_DISTANCE = 25000 |
+ SCROLL_STEP = 1000 |
+ MAX_SCROLL_RETRIES = 3 |
+ TIME_BEFORE_SCROLL_RETRY_IN_SECONDS = 1 |
+ TIME_TO_WAIT_BEFORE_STARTING_IN_SECONDS = 5 |
-class InfiniteScrollPage(page_module.Page): |
- def __init__(self, url, page_set, name, scroll_amount, delay, repeat, |
- credentials=None): |
- super(InfiniteScrollPage, self).__init__( |
- url=url, page_set=page_set, name=name, |
+ def __init__(self, story_set): |
+ super(_InfiniteScrollStory, self).__init__( |
+ page_set=story_set, url=self.URL, name=self.NAME, |
shared_page_state_class=shared_page_state.SharedPageState, |
- credentials_path='data/credentials.json') |
- self.credentials = credentials |
- self.script_to_evaluate_on_commit = STARTUP_SCRIPT |
- self.scroll_amount = scroll_amount |
- self.delay = delay |
- self.repeat = repeat |
+ credentials_path='data/credentials.json') |
+ # TODO(ulan): Remove this once crbug.com/541508 is fixed. |
+ self.script_to_evaluate_on_commit = ''' |
+ window.WebSocket = undefined; |
+ window.Worker = undefined; |
+ window.performance = undefined;''' |
nednguyen
2017/03/30 13:09:46
Does this make any of the page's JS fail? Seems a
ulan
2017/03/30 14:35:09
This part did not change with this CL. At the time
|
def RunPageInteractions(self, action_runner): |
- self._WaitAction(action_runner) |
- self._ScrollAction(action_runner, self.scroll_amount, self.delay, |
- self.repeat) |
- |
- def _ScrollAction(self, action_runner, scroll_amount, delay, repeat): |
- with action_runner.CreateInteraction('Begin'): |
- action_runner.tab.browser.DumpMemory() |
- with action_runner.CreateInteraction('Scrolling'): |
- action_runner.RepeatableBrowserDrivenScroll( |
- y_scroll_distance_ratio=scroll_amount, |
- repeat_delay_ms=delay, |
- repeat_count=repeat, |
- timeout=SCROLL_TIMEOUT_IN_SECONDS) |
- with action_runner.CreateInteraction('End'): |
- action_runner.tab.browser.DumpMemory() |
- |
- def _WaitAction(self, action_runner): |
with action_runner.CreateInteraction('Load'): |
action_runner.WaitForJavaScriptCondition( |
'document.body != null && ' |
'document.body.scrollHeight > window.innerHeight && ' |
'!document.body.addEventListener("touchstart", function() {})') |
with action_runner.CreateInteraction('Wait'): |
- action_runner.Wait(TIME_TO_WAIT_BEFORE_STARTING_IN_SECONDS) |
+ action_runner.Wait(self.TIME_TO_WAIT_BEFORE_STARTING_IN_SECONDS) |
with action_runner.CreateInteraction('GC'): |
action_runner.ForceGarbageCollection() |
+ with action_runner.CreateInteraction('Begin'): |
nednguyen
2017/03/30 13:09:46
not in this CL but these interactions are only nee
ulan
2017/03/30 14:35:08
Yep, will do in separete CL.
|
+ action_runner.tab.browser.DumpMemory() |
+ with action_runner.CreateInteraction('Scrolling'): |
+ self._Scroll(action_runner, self.SCROLL_DISTANCE, self.SCROLL_STEP) |
+ with action_runner.CreateInteraction('End'): |
+ action_runner.tab.browser.DumpMemory() |
+ def _Scroll(self, action_runner, distance, step_size): |
nednguyen
2017/03/30 13:09:46
this method seems useful & common enough to be an
ulan
2017/03/30 14:35:09
OK. I would wait until it is needed by another pag
|
+ """ This function scrolls the webpage by the given scroll distance in |
+ multiple steps, where each step (except the last one) has the given size. |
-class InfiniteScrollPageSet(story.StorySet): |
- """ Top pages that can be scrolled for many pages. """ |
+ If scrolling gets stuck, the functions retries scrolling MAX_SCROLL_RETRIES |
+ times waiting TIME_BEFORE_SCROLL_RETRY_IN_SECONDS seconds between retries. |
+ """ |
+ remaining = distance - action_runner.EvaluateJavaScript('window.scrollY') |
+ retry_count = 0 |
+ # Scroll until the window.scrollY is within 1 pixel of the target distance. |
+ while remaining > 1: |
+ action_runner.ScrollPage(distance=min(remaining, step_size) + 1) |
+ new_remaining = (distance - |
+ action_runner.EvaluateJavaScript('window.scrollY')) |
+ if remaining == new_remaining: |
+ # Scrolling is stuck. This can happen if the page is loading |
+ # resources. Give the page some time and retry scrolling. |
+ if retry_count == self.MAX_SCROLL_RETRIES: |
+ raise Exception('Scrolling stuck at %d' % remaining) |
+ retry_count += 1 |
+ action_runner.Wait(self.TIME_BEFORE_SCROLL_RETRY_IN_SECONDS) |
+ else: |
+ retry_count = 0 |
+ remaining = new_remaining |
+ |
+class DiscourseDesktopStory(_InfiniteScrollStory): |
+ NAME = 'discourse' |
+ URL = ('https://meta.discourse.org/t/the-official-discourse-tags-plugin' + |
+ '-discourse-tagging/26482') |
+ SUPPORTED_PLATFORMS = platforms.DESKTOP_ONLY |
+ |
+class DiscourseMobileStory(_InfiniteScrollStory): |
+ NAME = 'discourse' |
+ URL = ('https://meta.discourse.org/t/the-official-discourse-tags-plugin' + |
+ '-discourse-tagging/26482') |
+ SUPPORTED_PLATFORMS = platforms.MOBILE_ONLY |
+ SCROLL_DISTANCE = 15000 |
+ |
+class FacebookDesktopStory(_InfiniteScrollStory): |
+ NAME = 'facebook' |
+ URL = 'https://www.facebook.com/shakira' |
+ SUPPORTED_PLATFORMS = platforms.DESKTOP_ONLY |
+ |
+class FacebookMobileStory(_InfiniteScrollStory): |
+ NAME = 'facebook' |
+ URL = 'https://m.facebook.com/shakira' |
+ SUPPORTED_PLATFORMS = platforms.MOBILE_ONLY |
+ def RunNavigateSteps(self, action_runner): |
+ facebook_login.LoginWithMobileSite( |
+ action_runner, 'facebook3', self.credentials_path) |
+ super(FacebookMobileStory, self).RunNavigateSteps(action_runner) |
+ |
+class FlickrDesktopStory(_InfiniteScrollStory): |
+ NAME = 'flickr' |
+ URL = 'https://www.flickr.com/explore' |
+ SUPPORTED_PLATFORMS = platforms.DESKTOP_ONLY |
+ |
+class FlickrMobileStory(_InfiniteScrollStory): |
+ NAME = 'flickr' |
+ URL = 'https://www.flickr.com/explore' |
+ SUPPORTED_PLATFORMS = platforms.MOBILE_ONLY |
+ SCROLL_DISTANCE = 10000 |
+ |
+class PinterestMobileStory(_InfiniteScrollStory): |
+ NAME = 'pinterest' |
+ URL = 'https://www.pinterest.com/all' |
+ SUPPORTED_PLATFORMS = platforms.MOBILE_ONLY |
+ |
+class TumblrStory(_InfiniteScrollStory): |
+ NAME = 'tumblr' |
+ URL = 'http://techcrunch.tumblr.com/' |
+ |
+class TwitterDesktopStory(_InfiniteScrollStory): |
+ NAME = 'twitter' |
+ URL = 'https://twitter.com/taylorswift13' |
+ SUPPORTED_PLATFORMS = platforms.DESKTOP_ONLY |
+ |
+class InfiniteScrollStorySet(story.StorySet): |
+ """ Desktop story set. """ |
def __init__(self): |
- super(InfiniteScrollPageSet, self).__init__( |
+ super(InfiniteScrollStorySet, self).__init__( |
archive_data_file='data/infinite_scroll.json', |
cloud_storage_bucket=story.PARTNER_BUCKET) |
- # The scroll distance is chosen such that the page can be scrolled |
- # continuously through the test without hitting the end of the page. |
- SCROLL_FAR = 60 |
- SCROLL_PAGE = 1 |
- pages = [ |
- ('https://www.facebook.com/shakira', 'facebook', SCROLL_FAR, 0, 0), |
- ('https://twitter.com/taylorswift13', 'twitter', SCROLL_PAGE, 10, 30), |
- ('http://techcrunch.tumblr.com/', 'tumblr', SCROLL_FAR, 0, 0), |
- ('https://www.flickr.com/explore', 'flickr', SCROLL_FAR, 0, 0), |
- ('https://meta.discourse.org/t/the-official-discourse-tags-plugin-discourse-tagging/26482', |
- 'discourse', SCROLL_PAGE, 10, 30) |
- ] |
- for (url, name, scroll_amount, delay, repeat) in pages: |
- self.AddStory( |
- InfiniteScrollPage(url, self, name, scroll_amount, delay, repeat)) |
+ for story_class in _FindInfiniteScrollStoryClasses(platforms.DESKTOP): |
+ self.AddStory(story_class(self)) |
+ |
+class MobileInfiniteScrollStorySet(story.StorySet): |
+ """ Mobile story set. """ |
+ def __init__(self): |
+ super(MobileInfiniteScrollStorySet, self).__init__( |
+ archive_data_file='data/mobile_infinite_scroll.json', |
+ cloud_storage_bucket=story.PARTNER_BUCKET) |
+ for story_class in _FindInfiniteScrollStoryClasses(platforms.MOBILE): |
+ self.AddStory(story_class(self)) |
+ |
+def _FindInfiniteScrollStoryClasses(platform): |
+ # Sort the classes by their names so that their order is stable and |
+ # deterministic. |
+ for unused_cls_name, cls in sorted(discover.DiscoverClassesInModule( |
+ module=sys.modules[__name__], base_class=_InfiniteScrollStory, |
+ index_by_class_name=True).iteritems()): |
+ if platform in cls.SUPPORTED_PLATFORMS: |
+ yield cls |