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

Side by Side Diff: tools/chrome_proxy/webdriver/common.py

Issue 2528483004: Adds skeleton of new integration test framework. (Closed)
Patch Set: Fix nits. Created 4 years 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
OLDNEW
(Empty)
1 # Copyright 2016 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 import argparse
6 import json
7 import os
8 import shlex
9 import sys
10 import time
11 import traceback
12
13 sys.path.append(os.path.join(os.path.dirname(__file__), os.pardir, os.pardir,
14 os.pardir, 'third_party', 'webdriver', 'pylib'))
15 from selenium import webdriver
16 from selenium.webdriver.chrome.options import Options
17
18 # TODO(robertogden) add logging
19
20
21 def ParseFlags():
22 """
23 Parses the given command line arguments and returns an object with the flags
24 as properties.
25 """
26 parser = argparse.ArgumentParser()
27 parser.add_argument('--browser_args', nargs=1, type=str, help='Override '
28 'browser flags in code with these flags')
29 parser.add_argument('--via_header_matches', metavar='via_header', nargs=1,
30 default='1.1 Chrome-Compression-Proxy', help='What the via should match to '
31 'be considered valid')
32 parser.add_argument('--chrome_exec', nargs=1, type=str, help='The path to '
33 'the Chrome or Chromium executable')
34 parser.add_argument('chrome_driver', nargs=1, type=str, help='The path to '
35 'the ChromeDriver executable')
36 # TODO(robertogden) make this a logging statement
37 print 'DEBUG: Args=', json.dumps(vars(parser.parse_args(sys.argv[1:])))
38 return parser.parse_args(sys.argv[1:])
39
40 def HandleException(test_name=None):
41 """
42 Writes the exception being handled and a stack trace to stderr.
43 """
44 sys.stderr.write("**************************************\n")
45 sys.stderr.write("**************************************\n")
46 sys.stderr.write("** **\n")
47 sys.stderr.write("** UNCAUGHT EXCEPTION **\n")
48 sys.stderr.write("** **\n")
49 sys.stderr.write("**************************************\n")
50 sys.stderr.write("**************************************\n")
51 if test_name:
52 sys.stderr.write("Failed test: %s" % test_name)
53 traceback.print_exception(*sys.exc_info())
54 sys.exit(1)
55
56 class TestDriver:
57 """
58 This class is the tool that is used by every integration test to interact with
59 the Chromium browser and validate proper functionality. This class sits on top
60 of the Selenium Chrome Webdriver with added utility and helper functions for
61 Chrome-Proxy. This class should be used with Python's 'with' operator.
62 """
63
64 def __init__(self):
65 self._flags = ParseFlags()
66 self._driver = None
67 self.chrome_args = {}
RyanSturm 2016/11/29 19:31:46 can this be a set instead of a dict? I don't see m
Robert Ogden 2016/11/29 22:39:36 Done in follow up CL
68 self._url = ''
69
70 def __enter__(self):
71 return self
72
73 def __exit__(self, exc_type, exc_value, tb):
74 if self._driver:
75 self._StopDriver()
76
77 def _OverrideChromeArgs(self):
78 """
79 Overrides any given flags in the code with those given on the command line.
80 """
81 if self._flags.browser_args and len(self._flags.browser_args) > 0:
82 for a in shlex.split(self._flags.browser_args):
83 self.chrome_args[a] = True
84
85 def _StartDriver(self):
86 """
87 Parses the flags to pass to Chromium, then starts the ChromeDriver.
88 """
89 opts = Options()
90 for a in self.chrome_args:
91 opts.add_argument(a)
92 caps = {'loggingPrefs': {'performance': 'INFO'}}
93 if self._flags.chrome_exec:
94 caps['chrome.binary'] = self._flags.chrome_exec
95 driver = webdriver.Chrome(executable_path=self._flags.chrome_driver[0],
96 chrome_options=opts, desired_capabilities=caps)
97 driver.command_executor._commands.update({
98 'getAvailableLogTypes': ('GET', '/session/$sessionId/log/types'),
99 'getLog': ('POST', '/session/$sessionId/log')})
100 self._driver = driver
101
102 def _StopDriver(self):
103 """
104 Nicely stops the ChromeDriver.
105 """
106 self._driver.quit()
107 del self._driver
108
109 def AddChromeArgs(self, args):
110 """
111 Adds multiple arguments that will be passed to Chromium at start.
112 """
113 if not self.chrome_args:
114 self.chrome_args = {}
115 for a in args:
116 self.chrome_args[a] = True
117
118 def AddChromeArg(self, arg):
119 """
120 Adds a single argument that will be passed to Chromium at start.
121 """
122 if not self.chrome_args:
123 self.chrome_args = {}
124 self.chrome_args[arg] = True
125
126 def RemoveChromeArgs(self, args):
127 """
128 Removes multiple arguments that will no longer be passed to Chromium at
129 start.
130 """
131 if not self.chrome_args:
132 self.chrome_args = {}
133 return
134 for a in args:
135 del self.chrome_args[a]
136
137 def RemoveChromeArg(self, arg):
138 """
139 Removes a single argument that will no longer be passed to Chromium at
140 start.
141 """
142 if not self.chrome_args:
143 self.chrome_args = {}
144 return
145 del self.chrome_args[arg]
146
147 def ClearChromeArgs(self):
148 """
149 Removes all arguments from Chromium at start.
150 """
151 self.chrome_args = {}
152
153 def ClearCache(self):
154 """
155 Clears the browser cache. Important note: ChromeDriver automatically starts
156 a clean copy of Chrome on every instantiation.
157 """
158 self.ExecuteJavascript('if(window.chrome && chrome.benchmarking && '
159 'chrome.benchmarking.clearCache){chrome.benchmarking.clearCache(); '
160 'chrome.benchmarking.clearPredictorCache();chrome.benchmarking.'
161 'clearHostResolverCache();}')
162
163 # TODO(robertogden) use a smart page instead
164 def SetURL(self, url):
165 """
166 Sets the URL that the browser will navigate to during the test.
167 """
168 self._url = url
169
170 # TODO(robertogden) add timeout
171 def LoadPage(self):
172 """
173 Starts Chromium with any arguments previously given and navigates to the
174 previously given URL.
175 """
176 if not self._driver:
177 self._StartDriver()
178 self._driver.get(self._url)
179
180 # TODO(robertogden) add timeout
181 def ExecuteJavascript(self, script):
182 """
183 Executes the given javascript in the browser's current page as if it were on
184 the console. Returns a string of whatever the evaluation was.
185 """
186 if not self._driver:
187 self._StartDriver()
188 return self._driver.execute_script("return " + script)
RyanSturm 2016/11/29 19:31:46 What happens if LoadPage was not called (i.e., _St
Robert Ogden 2016/11/29 22:39:36 Chrome would start but would stay on a blank page.
189
190
191 class IntegrationTest:
192 """
193 A parent class for all integration tests with utility and assertion methods.
194 All methods starting with the word 'test' (ignoring case) will be called with
195 the RunAllTests() method which can be used in place of a main method.
196 """
197 def RunAllTests(self):
198 """
199 Runs all methods starting with the word 'test' (ignoring case) in the class.
200 Can be used in place of a main method to run all tests in a class.
201 """
202 methodList = [method for method in dir(self) if callable(getattr(self,
203 method)) and method.lower().startswith('test')]
204 for method in methodList:
205 try:
206 getattr(self, method)()
207 except Exception as e:
208 HandleException(method)
209
210 # TODO(robertogden) add some nice assertion functions
211
212 def Fail(self, msg):
213 sys.stderr.write("**************************************\n")
214 sys.stderr.write("**************************************\n")
215 sys.stderr.write("** **\n")
216 sys.stderr.write("** TEST FAILURE **\n")
217 sys.stderr.write("** **\n")
218 sys.stderr.write("**************************************\n")
219 sys.stderr.write("**************************************\n")
220 sys.stderr.write(msg, '\n')
221 sys.exit(1)
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698