Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 # Copyright 2015 The Chromium Authors. All rights reserved. | 1 # Copyright 2017 The Chromium Authors. All rights reserved. |
| 2 # Use of this source code is governed by a BSD-style license that can be | 2 # Use of this source code is governed by a BSD-style license that can be |
| 3 # found in the LICENSE file. | 3 # found in the LICENSE file. |
| 4 from telemetry.page import page as page_module | 4 |
| 5 import sys | |
| 6 | |
| 7 from page_sets.login_helpers import facebook_login | |
| 8 from page_sets.system_health import platforms | |
| 9 from telemetry.core import discover | |
| 10 from telemetry.page import page | |
| 5 from telemetry.page import shared_page_state | 11 from telemetry.page import shared_page_state |
| 6 from telemetry import story | 12 from telemetry import story |
| 7 | 13 |
| 8 TIME_TO_WAIT_BEFORE_STARTING_IN_SECONDS = 5 | 14 class _InfiniteScrollStory(page.Page): |
| 9 SCROLL_TIMEOUT_IN_SECONDS = 120 | 15 """ Base class for infinite scroll stories.""" |
| 10 | 16 |
| 11 # TODO(ulan): Remove this once crbug.com/541508 is fixed. | 17 NAME = NotImplemented |
| 12 STARTUP_SCRIPT = ''' | 18 URL = NotImplemented |
| 13 window.WebSocket = undefined; | 19 SUPPORTED_PLATFORMS = platforms.ALL_PLATFORMS |
| 14 window.Worker = undefined; | |
| 15 window.performance = undefined;''' | |
| 16 | 20 |
| 21 SCROLL_DISTANCE = 25000 | |
| 22 SCROLL_STEP = 1000 | |
| 23 MAX_SCROLL_RETRIES = 3 | |
| 24 TIME_BEFORE_SCROLL_RETRY_IN_SECONDS = 1 | |
| 25 TIME_TO_WAIT_BEFORE_STARTING_IN_SECONDS = 5 | |
| 17 | 26 |
| 18 class InfiniteScrollPage(page_module.Page): | 27 def __init__(self, story_set): |
| 19 def __init__(self, url, page_set, name, scroll_amount, delay, repeat, | 28 super(_InfiniteScrollStory, self).__init__( |
| 20 credentials=None): | 29 page_set=story_set, url=self.URL, name=self.NAME, |
| 21 super(InfiniteScrollPage, self).__init__( | |
| 22 url=url, page_set=page_set, name=name, | |
| 23 shared_page_state_class=shared_page_state.SharedPageState, | 30 shared_page_state_class=shared_page_state.SharedPageState, |
| 24 credentials_path='data/credentials.json') | 31 credentials_path='data/credentials.json') |
| 25 self.credentials = credentials | 32 # TODO(ulan): Remove this once crbug.com/541508 is fixed. |
| 26 self.script_to_evaluate_on_commit = STARTUP_SCRIPT | 33 self.script_to_evaluate_on_commit = ''' |
| 27 self.scroll_amount = scroll_amount | 34 window.WebSocket = undefined; |
| 28 self.delay = delay | 35 window.Worker = undefined; |
| 29 self.repeat = repeat | 36 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
| |
| 30 | 37 |
| 31 def RunPageInteractions(self, action_runner): | 38 def RunPageInteractions(self, action_runner): |
| 32 self._WaitAction(action_runner) | |
| 33 self._ScrollAction(action_runner, self.scroll_amount, self.delay, | |
| 34 self.repeat) | |
| 35 | |
| 36 def _ScrollAction(self, action_runner, scroll_amount, delay, repeat): | |
| 37 with action_runner.CreateInteraction('Begin'): | |
| 38 action_runner.tab.browser.DumpMemory() | |
| 39 with action_runner.CreateInteraction('Scrolling'): | |
| 40 action_runner.RepeatableBrowserDrivenScroll( | |
| 41 y_scroll_distance_ratio=scroll_amount, | |
| 42 repeat_delay_ms=delay, | |
| 43 repeat_count=repeat, | |
| 44 timeout=SCROLL_TIMEOUT_IN_SECONDS) | |
| 45 with action_runner.CreateInteraction('End'): | |
| 46 action_runner.tab.browser.DumpMemory() | |
| 47 | |
| 48 def _WaitAction(self, action_runner): | |
| 49 with action_runner.CreateInteraction('Load'): | 39 with action_runner.CreateInteraction('Load'): |
| 50 action_runner.WaitForJavaScriptCondition( | 40 action_runner.WaitForJavaScriptCondition( |
| 51 'document.body != null && ' | 41 'document.body != null && ' |
| 52 'document.body.scrollHeight > window.innerHeight && ' | 42 'document.body.scrollHeight > window.innerHeight && ' |
| 53 '!document.body.addEventListener("touchstart", function() {})') | 43 '!document.body.addEventListener("touchstart", function() {})') |
| 54 with action_runner.CreateInteraction('Wait'): | 44 with action_runner.CreateInteraction('Wait'): |
| 55 action_runner.Wait(TIME_TO_WAIT_BEFORE_STARTING_IN_SECONDS) | 45 action_runner.Wait(self.TIME_TO_WAIT_BEFORE_STARTING_IN_SECONDS) |
| 56 with action_runner.CreateInteraction('GC'): | 46 with action_runner.CreateInteraction('GC'): |
| 57 action_runner.ForceGarbageCollection() | 47 action_runner.ForceGarbageCollection() |
| 48 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.
| |
| 49 action_runner.tab.browser.DumpMemory() | |
| 50 with action_runner.CreateInteraction('Scrolling'): | |
| 51 self._Scroll(action_runner, self.SCROLL_DISTANCE, self.SCROLL_STEP) | |
| 52 with action_runner.CreateInteraction('End'): | |
| 53 action_runner.tab.browser.DumpMemory() | |
| 58 | 54 |
| 55 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
| |
| 56 """ This function scrolls the webpage by the given scroll distance in | |
| 57 multiple steps, where each step (except the last one) has the given size. | |
| 59 | 58 |
| 60 class InfiniteScrollPageSet(story.StorySet): | 59 If scrolling gets stuck, the functions retries scrolling MAX_SCROLL_RETRIES |
| 61 """ Top pages that can be scrolled for many pages. """ | 60 times waiting TIME_BEFORE_SCROLL_RETRY_IN_SECONDS seconds between retries. |
| 61 """ | |
| 62 remaining = distance - action_runner.EvaluateJavaScript('window.scrollY') | |
| 63 retry_count = 0 | |
| 64 # Scroll until the window.scrollY is within 1 pixel of the target distance. | |
| 65 while remaining > 1: | |
| 66 action_runner.ScrollPage(distance=min(remaining, step_size) + 1) | |
| 67 new_remaining = (distance - | |
| 68 action_runner.EvaluateJavaScript('window.scrollY')) | |
| 69 if remaining == new_remaining: | |
| 70 # Scrolling is stuck. This can happen if the page is loading | |
| 71 # resources. Give the page some time and retry scrolling. | |
| 72 if retry_count == self.MAX_SCROLL_RETRIES: | |
| 73 raise Exception('Scrolling stuck at %d' % remaining) | |
| 74 retry_count += 1 | |
| 75 action_runner.Wait(self.TIME_BEFORE_SCROLL_RETRY_IN_SECONDS) | |
| 76 else: | |
| 77 retry_count = 0 | |
| 78 remaining = new_remaining | |
| 79 | |
| 80 class DiscourseDesktopStory(_InfiniteScrollStory): | |
| 81 NAME = 'discourse' | |
| 82 URL = ('https://meta.discourse.org/t/the-official-discourse-tags-plugin' + | |
| 83 '-discourse-tagging/26482') | |
| 84 SUPPORTED_PLATFORMS = platforms.DESKTOP_ONLY | |
| 85 | |
| 86 class DiscourseMobileStory(_InfiniteScrollStory): | |
| 87 NAME = 'discourse' | |
| 88 URL = ('https://meta.discourse.org/t/the-official-discourse-tags-plugin' + | |
| 89 '-discourse-tagging/26482') | |
| 90 SUPPORTED_PLATFORMS = platforms.MOBILE_ONLY | |
| 91 SCROLL_DISTANCE = 15000 | |
| 92 | |
| 93 class FacebookDesktopStory(_InfiniteScrollStory): | |
| 94 NAME = 'facebook' | |
| 95 URL = 'https://www.facebook.com/shakira' | |
| 96 SUPPORTED_PLATFORMS = platforms.DESKTOP_ONLY | |
| 97 | |
| 98 class FacebookMobileStory(_InfiniteScrollStory): | |
| 99 NAME = 'facebook' | |
| 100 URL = 'https://m.facebook.com/shakira' | |
| 101 SUPPORTED_PLATFORMS = platforms.MOBILE_ONLY | |
| 102 def RunNavigateSteps(self, action_runner): | |
| 103 facebook_login.LoginWithMobileSite( | |
| 104 action_runner, 'facebook3', self.credentials_path) | |
| 105 super(FacebookMobileStory, self).RunNavigateSteps(action_runner) | |
| 106 | |
| 107 class FlickrDesktopStory(_InfiniteScrollStory): | |
| 108 NAME = 'flickr' | |
| 109 URL = 'https://www.flickr.com/explore' | |
| 110 SUPPORTED_PLATFORMS = platforms.DESKTOP_ONLY | |
| 111 | |
| 112 class FlickrMobileStory(_InfiniteScrollStory): | |
| 113 NAME = 'flickr' | |
| 114 URL = 'https://www.flickr.com/explore' | |
| 115 SUPPORTED_PLATFORMS = platforms.MOBILE_ONLY | |
| 116 SCROLL_DISTANCE = 10000 | |
| 117 | |
| 118 class PinterestMobileStory(_InfiniteScrollStory): | |
| 119 NAME = 'pinterest' | |
| 120 URL = 'https://www.pinterest.com/all' | |
| 121 SUPPORTED_PLATFORMS = platforms.MOBILE_ONLY | |
| 122 | |
| 123 class TumblrStory(_InfiniteScrollStory): | |
| 124 NAME = 'tumblr' | |
| 125 URL = 'http://techcrunch.tumblr.com/' | |
| 126 | |
| 127 class TwitterDesktopStory(_InfiniteScrollStory): | |
| 128 NAME = 'twitter' | |
| 129 URL = 'https://twitter.com/taylorswift13' | |
| 130 SUPPORTED_PLATFORMS = platforms.DESKTOP_ONLY | |
| 131 | |
| 132 class InfiniteScrollStorySet(story.StorySet): | |
| 133 """ Desktop story set. """ | |
| 62 def __init__(self): | 134 def __init__(self): |
| 63 super(InfiniteScrollPageSet, self).__init__( | 135 super(InfiniteScrollStorySet, self).__init__( |
| 64 archive_data_file='data/infinite_scroll.json', | 136 archive_data_file='data/infinite_scroll.json', |
| 65 cloud_storage_bucket=story.PARTNER_BUCKET) | 137 cloud_storage_bucket=story.PARTNER_BUCKET) |
| 66 # The scroll distance is chosen such that the page can be scrolled | 138 for story_class in _FindInfiniteScrollStoryClasses(platforms.DESKTOP): |
| 67 # continuously through the test without hitting the end of the page. | 139 self.AddStory(story_class(self)) |
| 68 SCROLL_FAR = 60 | 140 |
| 69 SCROLL_PAGE = 1 | 141 class MobileInfiniteScrollStorySet(story.StorySet): |
| 70 pages = [ | 142 """ Mobile story set. """ |
| 71 ('https://www.facebook.com/shakira', 'facebook', SCROLL_FAR, 0, 0), | 143 def __init__(self): |
| 72 ('https://twitter.com/taylorswift13', 'twitter', SCROLL_PAGE, 10, 30), | 144 super(MobileInfiniteScrollStorySet, self).__init__( |
| 73 ('http://techcrunch.tumblr.com/', 'tumblr', SCROLL_FAR, 0, 0), | 145 archive_data_file='data/mobile_infinite_scroll.json', |
| 74 ('https://www.flickr.com/explore', 'flickr', SCROLL_FAR, 0, 0), | 146 cloud_storage_bucket=story.PARTNER_BUCKET) |
| 75 ('https://meta.discourse.org/t/the-official-discourse-tags-plugin-discou rse-tagging/26482', | 147 for story_class in _FindInfiniteScrollStoryClasses(platforms.MOBILE): |
| 76 'discourse', SCROLL_PAGE, 10, 30) | 148 self.AddStory(story_class(self)) |
| 77 ] | 149 |
| 78 for (url, name, scroll_amount, delay, repeat) in pages: | 150 def _FindInfiniteScrollStoryClasses(platform): |
| 79 self.AddStory( | 151 # Sort the classes by their names so that their order is stable and |
| 80 InfiniteScrollPage(url, self, name, scroll_amount, delay, repeat)) | 152 # deterministic. |
| 153 for unused_cls_name, cls in sorted(discover.DiscoverClassesInModule( | |
| 154 module=sys.modules[__name__], base_class=_InfiniteScrollStory, | |
| 155 index_by_class_name=True).iteritems()): | |
| 156 if platform in cls.SUPPORTED_PLATFORMS: | |
| 157 yield cls | |
| OLD | NEW |