Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(320)

Side by Side Diff: chrome/test/functional/perf_endure.py

Issue 10803002: Run Chrome Endure tests with network simulation via Web Page Replay. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Tests by default do not have WPR support. Created 8 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 #!/usr/bin/env python 1 #!/usr/bin/env python
2 # Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 # Copyright (c) 2012 The Chromium Authors. All rights reserved.
3 # Use of this source code is governed by a BSD-style license that can be 3 # Use of this source code is governed by a BSD-style license that can be
4 # found in the LICENSE file. 4 # found in the LICENSE file.
5 5
6 """Performance tests for Chrome Endure (long-running perf tests on Chrome). 6 """Performance tests for Chrome Endure (long-running perf tests on Chrome).
7 7
8 This module accepts the following environment variable inputs: 8 This module accepts the following environment variable inputs:
9 TEST_LENGTH: The number of seconds in which to run each test. 9 TEST_LENGTH: The number of seconds in which to run each test.
10 PERF_STATS_INTERVAL: The number of seconds to wait in-between each sampling 10 PERF_STATS_INTERVAL: The number of seconds to wait in-between each sampling
(...skipping 15 matching lines...) Expand all
26 import time 26 import time
27 27
28 import perf 28 import perf
29 import pyauto_functional # Must be imported before pyauto. 29 import pyauto_functional # Must be imported before pyauto.
30 import pyauto 30 import pyauto
31 import pyauto_errors 31 import pyauto_errors
32 import pyauto_utils 32 import pyauto_utils
33 import remote_inspector_client 33 import remote_inspector_client
34 import selenium.common.exceptions 34 import selenium.common.exceptions
35 from selenium.webdriver.support.ui import WebDriverWait 35 from selenium.webdriver.support.ui import WebDriverWait
36 import webpagereplay
36 37
37 38
38 class NotSupportedEnvironmentError(RuntimeError): 39 class NotSupportedEnvironmentError(RuntimeError):
39 """Represent an error raised since the environment (OS) is not supported.""" 40 """Represent an error raised since the environment (OS) is not supported."""
40 pass 41 pass
41 42
43
42 class ChromeEndureBaseTest(perf.BasePerfTest): 44 class ChromeEndureBaseTest(perf.BasePerfTest):
43 """Implements common functionality for all Chrome Endure tests. 45 """Implements common functionality for all Chrome Endure tests.
44 46
45 All Chrome Endure test classes should inherit from this class. 47 All Chrome Endure test classes should inherit from this class.
46 """ 48 """
47 49
48 _DEFAULT_TEST_LENGTH_SEC = 60 * 60 * 6 # Tests run for 6 hours. 50 _DEFAULT_TEST_LENGTH_SEC = 60 * 60 * 6 # Tests run for 6 hours.
49 _GET_PERF_STATS_INTERVAL = 60 * 5 # Measure perf stats every 5 minutes. 51 _GET_PERF_STATS_INTERVAL = 60 * 5 # Measure perf stats every 5 minutes.
50 # TODO(dennisjeffrey): Do we still need to tolerate errors? 52 # TODO(dennisjeffrey): Do we still need to tolerate errors?
51 _ERROR_COUNT_THRESHOLD = 50 # Number of ChromeDriver errors to tolerate. 53 _ERROR_COUNT_THRESHOLD = 50 # Number of ChromeDriver errors to tolerate.
52 _DEEP_MEMORY_PROFILE = False 54 _DEEP_MEMORY_PROFILE = False
53 _DEEP_MEMORY_PROFILE_INTERVAL = _GET_PERF_STATS_INTERVAL 55 _DEEP_MEMORY_PROFILE_INTERVAL = _GET_PERF_STATS_INTERVAL
54 _DEEP_MEMORY_PROFILE_SAVE = False 56 _DEEP_MEMORY_PROFILE_SAVE = False
55 57
56 _DMPROF_DIR_PATH = os.path.join( 58 _DMPROF_DIR_PATH = os.path.join(
57 os.path.dirname(__file__), os.pardir, os.pardir, os.pardir, 59 os.path.dirname(__file__), os.pardir, os.pardir, os.pardir,
58 'tools', 'deep_memory_profiler') 60 'tools', 'deep_memory_profiler')
59 61
60 _DMPROF_SCRIPT_PATH = os.path.join(_DMPROF_DIR_PATH, 'dmprof') 62 _DMPROF_SCRIPT_PATH = os.path.join(_DMPROF_DIR_PATH, 'dmprof')
61 63
62 _CHROME_BIN_PATH = os.path.join(perf.BasePerfTest.BrowserPath(), 'chrome') 64 _CHROME_BIN_PATH = os.path.join(perf.BasePerfTest.BrowserPath(), 'chrome')
63 65
64 def setUp(self): 66 def setUp(self):
67 # The environment variable for the usage of Web Page Replay.
68 # It must be parsed before perf.BasePerfTest.setUp()
69 self._use_wpr = self._NeedReplayServer()
dennis_jeffrey 2012/08/03 19:39:54 As discussed offline, let's follow this behavior:
fdeng1 2012/08/06 20:58:24 Done.
70 # Do NOT mannually set WPR_RECORD for the purpose of
dennis_jeffrey 2012/08/03 19:39:54 mannually --> manually
fdeng1 2012/08/06 20:58:24 Done.
71 # making recording archive for endure tests. Run record_endure.py instead.
72 if self._use_wpr:
73 self._is_replay_mode = 'WPR_RECORD' not in os.environ
74
65 # The environment variables for the Deep Memory Profiler must be set 75 # The environment variables for the Deep Memory Profiler must be set
66 # before perf.BasePerfTest.setUp() to inherit them to Chrome. 76 # before perf.BasePerfTest.setUp() to inherit them to Chrome.
67 self._deep_memory_profile = self._GetDeepMemoryProfileEnv( 77 self._deep_memory_profile = self._GetDeepMemoryProfileEnv(
68 'DEEP_MEMORY_PROFILE', bool, self._DEEP_MEMORY_PROFILE) 78 'DEEP_MEMORY_PROFILE', bool, self._DEEP_MEMORY_PROFILE)
69 79
70 self._deep_memory_profile_interval = self._GetDeepMemoryProfileEnv( 80 self._deep_memory_profile_interval = self._GetDeepMemoryProfileEnv(
71 'DEEP_MEMORY_PROFILE_INTERVAL', int, self._DEEP_MEMORY_PROFILE_INTERVAL) 81 'DEEP_MEMORY_PROFILE_INTERVAL', int, self._DEEP_MEMORY_PROFILE_INTERVAL)
72 82
73 if self._deep_memory_profile: 83 if self._deep_memory_profile:
74 if not self.IsLinux(): 84 if not self.IsLinux():
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
110 self._remote_inspector_client = ( 120 self._remote_inspector_client = (
111 remote_inspector_client.RemoteInspectorClient()) 121 remote_inspector_client.RemoteInspectorClient())
112 logging.info('Connection to remote inspector set up successfully.') 122 logging.info('Connection to remote inspector set up successfully.')
113 123
114 self._test_start_time = 0 124 self._test_start_time = 0
115 self._num_errors = 0 125 self._num_errors = 0
116 self._events_to_output = [] 126 self._events_to_output = []
117 self._deep_memory_profile_json_file = None 127 self._deep_memory_profile_json_file = None
118 self._deep_memory_profile_last_json_filename = '' 128 self._deep_memory_profile_last_json_filename = ''
119 self._deep_memory_profile_proc = None 129 self._deep_memory_profile_proc = None
130 self._StartReplayServerIfNecessary()
120 131
121 def tearDown(self): 132 def tearDown(self):
122 logging.info('Terminating connection to remote inspector...') 133 logging.info('Terminating connection to remote inspector...')
123 self._remote_inspector_client.Stop() 134 self._remote_inspector_client.Stop()
124 logging.info('Connection to remote inspector terminated.') 135 logging.info('Connection to remote inspector terminated.')
125 if self._deep_memory_profile: 136 if self._deep_memory_profile:
126 # TODO(dmikurube): Stop to set HEAP_PROFILE_TIME_INTERVAL in setUp when 137 # TODO(dmikurube): Stop to set HEAP_PROFILE_TIME_INTERVAL in setUp when
127 # PyAuto supports to dump renderer heap profile. 138 # PyAuto supports to dump renderer heap profile.
128 del os.environ['HEAP_PROFILE_TIME_INTERVAL'] 139 del os.environ['HEAP_PROFILE_TIME_INTERVAL']
129 del os.environ['DEEP_HEAP_PROFILE'] 140 del os.environ['DEEP_HEAP_PROFILE']
130 del os.environ['HEAP_PROFILE_MMAP'] 141 del os.environ['HEAP_PROFILE_MMAP']
131 del os.environ['HEAPPROFILE'] 142 del os.environ['HEAPPROFILE']
132 143
133 # Must be done at end of this function except for post-cleaning after 144 # Must be done at end of this function except for post-cleaning after
134 # Chrome finishes. 145 # Chrome finishes.
135 perf.BasePerfTest.tearDown(self) 146 perf.BasePerfTest.tearDown(self)
136 147
137 # Remove the temporary directory after Chrome finishes in tearDown. 148 # Remove the temporary directory after Chrome finishes in tearDown.
138 if (self._deep_memory_profile and 149 if (self._deep_memory_profile and
139 not self._deep_memory_profile_save and 150 not self._deep_memory_profile_save and
140 self._deep_tempdir): 151 self._deep_tempdir):
141 pyauto_utils.RemovePath(self._deep_tempdir) 152 pyauto_utils.RemovePath(self._deep_tempdir)
153 # Must be done after perf.BasePerfTest.tearDown()
154 self._StopReplayServerIfNecessary()
155
156 def _NeedReplayServer(self):
157 """Check whether the test needs to run against Web Page Replay server.
158
159 Override this function to turn on Web Page Replay for a test.
160
161 Returns:
162 True if need replay server otherwise False.
163 """
164 return False
fdeng1 2012/08/03 16:47:06 Change this function so that by default, tests wil
dennis_jeffrey 2012/08/03 19:39:54 Let's get rid of this function completely. If a t
fdeng1 2012/08/06 20:58:24 Done.
165
166 def _GenArchiveName(self):
167 """Returns the Web Page Replay archive name that corresponds to a test.
168
169 Use test class name as archive name, e.g. ChromeEndureGmailTest.wpr
170 Override this function to allow other names.
171
dennis_jeffrey 2012/08/03 19:39:54 make a note that this assumes that we only have 1
fdeng1 2012/08/06 20:58:24 Added a note to doc string On 2012/08/03 19:39:54,
172 Returns:
173 An archive name generated using test class name.
174 """
175 # Use class name as archive name.
176 return self.id().split('.')[1] + '.wpr'
142 177
143 def _GetDeepMemoryProfileEnv(self, env_name, converter, default): 178 def _GetDeepMemoryProfileEnv(self, env_name, converter, default):
144 """Returns a converted environment variable for the Deep Memory Profiler. 179 """Returns a converted environment variable for the Deep Memory Profiler.
145 180
146 Args: 181 Args:
147 env_name: A string name of an environment variable. 182 env_name: A string name of an environment variable.
148 converter: A function taking a string to convert an environment variable. 183 converter: A function taking a string to convert an environment variable.
149 default: A value used if the environment variable is not specified. 184 default: A value used if the environment variable is not specified.
150 185
151 Returns: 186 Returns:
(...skipping 21 matching lines...) Expand all
173 # The same with setUp, but need to fetch the environment variable since 208 # The same with setUp, but need to fetch the environment variable since
174 # ExtraChromeFlags is called before setUp. 209 # ExtraChromeFlags is called before setUp.
175 deep_memory_profile = self._GetDeepMemoryProfileEnv( 210 deep_memory_profile = self._GetDeepMemoryProfileEnv(
176 'DEEP_MEMORY_PROFILE', bool, self._DEEP_MEMORY_PROFILE) 211 'DEEP_MEMORY_PROFILE', bool, self._DEEP_MEMORY_PROFILE)
177 212
178 # Ensure Chrome enables remote debugging on port 9222. This is required to 213 # Ensure Chrome enables remote debugging on port 9222. This is required to
179 # interact with Chrome's remote inspector. 214 # interact with Chrome's remote inspector.
180 extra_flags = ['--remote-debugging-port=9222'] 215 extra_flags = ['--remote-debugging-port=9222']
181 if deep_memory_profile: 216 if deep_memory_profile:
182 extra_flags.append('--no-sandbox') 217 extra_flags.append('--no-sandbox')
183 return (perf.BasePerfTest.ExtraChromeFlags(self) + extra_flags) 218 if self._use_wpr:
219 extra_flags.extend(ChromeEndureReplay.CHROME_FLAGS)
220 return perf.BasePerfTest.ExtraChromeFlags(self) + extra_flags
184 221
185 def _OnTimelineEvent(self, event_info): 222 def _OnTimelineEvent(self, event_info):
186 """Invoked by the Remote Inspector Client when a timeline event occurs. 223 """Invoked by the Remote Inspector Client when a timeline event occurs.
187 224
188 Args: 225 Args:
189 event_info: A dictionary containing raw information associated with a 226 event_info: A dictionary containing raw information associated with a
190 timeline event received from Chrome's remote inspector. Refer to 227 timeline event received from Chrome's remote inspector. Refer to
191 chrome/src/third_party/WebKit/Source/WebCore/inspector/Inspector.json 228 chrome/src/third_party/WebKit/Source/WebCore/inspector/Inspector.json
192 for the format of this dictionary. 229 for the format of this dictionary.
193 """ 230 """
(...skipping 339 matching lines...) Expand 10 before | Expand all | Expand 10 after
533 try: 570 try:
534 element = self._GetElement(driver.find_element_by_xpath, xpath) 571 element = self._GetElement(driver.find_element_by_xpath, xpath)
535 element.click() 572 element.click()
536 except (selenium.common.exceptions.StaleElementReferenceException, 573 except (selenium.common.exceptions.StaleElementReferenceException,
537 selenium.common.exceptions.TimeoutException) as e: 574 selenium.common.exceptions.TimeoutException) as e:
538 logging.exception('WebDriver exception: %s' % e) 575 logging.exception('WebDriver exception: %s' % e)
539 return False 576 return False
540 577
541 return True 578 return True
542 579
580 def _StartReplayServerIfNecessary(self):
581 """Start replay server if necessary.
582
583 This method needs to be called BEFORE any connection (which is supposed
584 to go through the Web Page Replay server) occurs.
585 """
586 if self._use_wpr and self._is_replay_mode:
587 archive_name = self._GenArchiveName()
588 self._wpr_server = ChromeEndureReplay.ReplayServer(archive_name)
589 self._wpr_server.StartServer()
590 logging.info('Web Page Replay server has started in Replay mode.')
591
592 def _StopReplayServerIfNecessary(self):
593 """Stop the Web Page Replay server if necessary.
594
595 This method has to be called AFTER all network connections which go
596 through Web Page Replay server have shut down. Otherwise the
597 Web Page Replay server will hang to wait for them. A good
598 place is to call it at the end of the teardown process.
599 """
600 if self._use_wpr and self._is_replay_mode:
601 self._wpr_server.StopServer()
602 logging.info('The Web Page Replay server stopped.')
603
543 604
544 class ChromeEndureControlTest(ChromeEndureBaseTest): 605 class ChromeEndureControlTest(ChromeEndureBaseTest):
545 """Control tests for Chrome Endure.""" 606 """Control tests for Chrome Endure."""
546 607
547 _WEBAPP_NAME = 'Control' 608 _WEBAPP_NAME = 'Control'
548 _TAB_TITLE_SUBSTRING = 'Chrome Endure Control Test' 609 _TAB_TITLE_SUBSTRING = 'Chrome Endure Control Test'
549 610
550 def testControlAttachDetachDOMTree(self): 611 def testControlAttachDetachDOMTree(self):
551 """Continually attach and detach a DOM tree from a basic document.""" 612 """Continually attach and detach a DOM tree from a basic document."""
552 test_description = 'AttachDetachDOMTree' 613 test_description = 'AttachDetachDOMTree'
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after
616 677
617 # Wait until Gmail's 'canvas_frame' loads and the 'Inbox' link is present. 678 # Wait until Gmail's 'canvas_frame' loads and the 'Inbox' link is present.
618 # TODO(dennisjeffrey): Check with the Gmail team to see if there's a better 679 # TODO(dennisjeffrey): Check with the Gmail team to see if there's a better
619 # way to tell when the webpage is ready for user interaction. 680 # way to tell when the webpage is ready for user interaction.
620 self._wait.until( 681 self._wait.until(
621 self._SwitchToCanvasFrame) # Raises exception if the timeout is hit. 682 self._SwitchToCanvasFrame) # Raises exception if the timeout is hit.
622 # Wait for the inbox to appear. 683 # Wait for the inbox to appear.
623 self.WaitForDomNode('//a[starts-with(@title, "Inbox")]', 684 self.WaitForDomNode('//a[starts-with(@title, "Inbox")]',
624 frame_xpath=self._FRAME_XPATH) 685 frame_xpath=self._FRAME_XPATH)
625 686
687 def _NeedReplayServer(self):
688 """Check whether the test needs to run against Web Page Replay server.
689
690 Returns:
691 True if need replay server otherwise False.
692
693 Environment variable:
694 ENDURE_NO_WPR: if set, do not need replay server
695 """
696 if 'ENDURE_NO_WPR' in os.environ:
697 return False
698 else:
699 return True
700
626 def _SwitchToCanvasFrame(self, driver): 701 def _SwitchToCanvasFrame(self, driver):
627 """Switch the WebDriver to Gmail's 'canvas_frame', if it's available. 702 """Switch the WebDriver to Gmail's 'canvas_frame', if it's available.
628 703
629 Args: 704 Args:
630 driver: A selenium.webdriver.remote.webdriver.WebDriver object. 705 driver: A selenium.webdriver.remote.webdriver.WebDriver object.
631 706
632 Returns: 707 Returns:
633 True, if the switch to Gmail's 'canvas_frame' is successful, or 708 True, if the switch to Gmail's 'canvas_frame' is successful, or
634 False if not. 709 False if not.
635 """ 710 """
(...skipping 315 matching lines...) Expand 10 before | Expand all | Expand 10 after
951 self.NavigateToURL('http://docs.google.com') 1026 self.NavigateToURL('http://docs.google.com')
952 self.assertTrue( 1027 self.assertTrue(
953 self.WaitUntil(lambda: self._TAB_TITLE_SUBSTRING in 1028 self.WaitUntil(lambda: self._TAB_TITLE_SUBSTRING in
954 self.GetActiveTabTitle(), 1029 self.GetActiveTabTitle(),
955 timeout=60, expect_retval=True, retry_sleep=1), 1030 timeout=60, expect_retval=True, retry_sleep=1),
956 msg='Timed out waiting for Docs to load. Tab title is: %s' % 1031 msg='Timed out waiting for Docs to load. Tab title is: %s' %
957 self.GetActiveTabTitle()) 1032 self.GetActiveTabTitle())
958 1033
959 self._driver = self.NewWebDriver() 1034 self._driver = self.NewWebDriver()
960 1035
1036 def _NeedReplayServer(self):
1037 """Check whether the test needs to run against Web Page Replay server.
1038
1039 Returns:
1040 True if need replay server otherwise False.
1041
1042 Environment variable:
1043 ENDURE_NO_WPR: if set, do not need replay server
1044 """
1045 if 'ENDURE_NO_WPR' in os.environ:
1046 return False
1047 else:
1048 return True
1049
961 def testDocsAlternatelyClickLists(self): 1050 def testDocsAlternatelyClickLists(self):
962 """Alternates between two different document lists. 1051 """Alternates between two different document lists.
963 1052
964 This test alternately clicks the "Shared with me" and "My Drive" buttons in 1053 This test alternately clicks the "Shared with me" and "My Drive" buttons in
965 Google Docs, and periodically gathers performance stats that may reveal 1054 Google Docs, and periodically gathers performance stats that may reveal
966 memory bloat. 1055 memory bloat.
967 """ 1056 """
968 test_description = 'AlternateLists' 1057 test_description = 'AlternateLists'
969 1058
970 def scenario(): 1059 def scenario():
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after
1010 # Log into a test Google account and open up Google Plus. 1099 # Log into a test Google account and open up Google Plus.
1011 self._LoginToGoogleAccount() 1100 self._LoginToGoogleAccount()
1012 self.NavigateToURL('http://plus.google.com') 1101 self.NavigateToURL('http://plus.google.com')
1013 loaded_tab_title = self.GetActiveTabTitle() 1102 loaded_tab_title = self.GetActiveTabTitle()
1014 self.assertTrue(self._TAB_TITLE_SUBSTRING in loaded_tab_title, 1103 self.assertTrue(self._TAB_TITLE_SUBSTRING in loaded_tab_title,
1015 msg='Loaded tab title does not contain "%s": "%s"' % 1104 msg='Loaded tab title does not contain "%s": "%s"' %
1016 (self._TAB_TITLE_SUBSTRING, loaded_tab_title)) 1105 (self._TAB_TITLE_SUBSTRING, loaded_tab_title))
1017 1106
1018 self._driver = self.NewWebDriver() 1107 self._driver = self.NewWebDriver()
1019 1108
1109 def _NeedReplayServer(self):
1110 """Check whether the test needs to run against Web Page Replay server.
1111
1112 Returns:
1113 True if need replay server otherwise False.
1114
1115 Environment variable:
1116 ENDURE_NO_WPR: if set, do not need replay server
1117 """
1118 if 'ENDURE_NO_WPR' in os.environ:
1119 return False
1120 else:
1121 return True
1122
1020 def testPlusAlternatelyClickStreams(self): 1123 def testPlusAlternatelyClickStreams(self):
1021 """Alternates between two different streams. 1124 """Alternates between two different streams.
1022 1125
1023 This test alternately clicks the "Friends" and "Family" buttons using 1126 This test alternately clicks the "Friends" and "Family" buttons using
1024 Google Plus, and periodically gathers performance stats that may reveal 1127 Google Plus, and periodically gathers performance stats that may reveal
1025 memory bloat. 1128 memory bloat.
1026 """ 1129 """
1027 test_description = 'AlternateStreams' 1130 test_description = 'AlternateStreams'
1028 1131
1029 # TODO(dennisjeffrey): Remove following line once crosbug.com/32357 is 1132 # TODO(dennisjeffrey): Remove following line once crosbug.com/32357 is
(...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after
1117 except (pyauto_errors.JSONInterfaceError, 1220 except (pyauto_errors.JSONInterfaceError,
1118 pyauto_errors.JavascriptRuntimeError): 1221 pyauto_errors.JavascriptRuntimeError):
1119 self._num_errors += 1 1222 self._num_errors += 1
1120 1223
1121 time.sleep(1) 1224 time.sleep(1)
1122 1225
1123 self._RunEndureTest(self._WEBAPP_NAME, self._TAB_TITLE_SUBSTRING, 1226 self._RunEndureTest(self._WEBAPP_NAME, self._TAB_TITLE_SUBSTRING,
1124 test_description, scenario) 1227 test_description, scenario)
1125 1228
1126 1229
1230 class ChromeEndureReplay(object):
1231 """Run Chrome Endure tests with network simulation via Web Page Replay."""
1232
1233 _PATHS = {
1234 'archive':
1235 'src/chrome/test/data/pyauto_private/webpagereplay/{archive_name}',
1236 'scripts':
1237 'src/chrome/test/data/chrome_endure/webpagereplay/wpr_deterministic.js',
1238 }
1239 CHROME_FLAGS = webpagereplay.CHROME_FLAGS
1240
1241 @classmethod
1242 def Path(cls, key, **kwargs):
1243 return perf.FormatChromePath(cls._PATHS[key], **kwargs)
1244
1245 @classmethod
1246 def ReplayServer(cls, archive_name):
1247 """Creat a replay server."""
1248 # Inject customized scripts for Google webapps.
1249 # See the java script file for details.
1250 scripts = cls.Path('scripts')
1251 if not os.path.exists(scripts):
1252 raise webpagereplay.ReplayNotFoundError('injected scripts', scripts)
1253 replay_options = ['--inject_scripts', scripts]
1254 archive_path = cls.Path('archive', archive_name=archive_name)
1255 return webpagereplay.ReplayServer(archive_path, replay_options)
1256
1257
1127 if __name__ == '__main__': 1258 if __name__ == '__main__':
1128 pyauto_functional.Main() 1259 pyauto_functional.Main()
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698