| OLD | NEW |
| (Empty) | |
| 1 #!/usr/bin/env python |
| 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 |
| 4 # found in the LICENSE file. |
| 5 |
| 6 """Test fixture for tests involving installing/updating Chrome. |
| 7 |
| 8 Provides an interface to install or update chrome from within a testcase, and |
| 9 allows users to run tests using installed version of Chrome. User and system |
| 10 level installations are supported, and either one can be used for running the |
| 11 tests. Currently the only platform it supports is Windows. |
| 12 """ |
| 13 |
| 14 import atexit |
| 15 import logging |
| 16 import optparse |
| 17 import os |
| 18 import platform |
| 19 import re |
| 20 import shutil |
| 21 import stat |
| 22 import sys |
| 23 import tempfile |
| 24 import unittest |
| 25 import urllib |
| 26 |
| 27 import chrome_installer_win |
| 28 |
| 29 _DIRECTORY = os.path.dirname(os.path.abspath(__file__)) |
| 30 sys.path.append(os.path.join(os.path.dirname(_DIRECTORY), 'pyautolib')) |
| 31 sys.path.append(os.path.join(_DIRECTORY, os.path.pardir, os.path.pardir, |
| 32 os.path.pardir, 'third_party', 'webdriver', |
| 33 'pylib')) |
| 34 |
| 35 # This import should go after sys.path is set appropriately. |
| 36 import pyauto_utils |
| 37 import selenium.webdriver.chrome.service as service |
| 38 from selenium import webdriver |
| 39 |
| 40 |
| 41 def MakeTempDir(parent_dir=None): |
| 42 """Creates a temporary directory and returns an absolute path to it. |
| 43 |
| 44 The temporary directory is automatically deleted when the python interpreter |
| 45 exits normally. |
| 46 |
| 47 Args: |
| 48 parent_dir: the directory to create the temp dir in. If None, the system |
| 49 temp dir is used. |
| 50 |
| 51 Returns: |
| 52 The absolute path to the temporary directory. |
| 53 """ |
| 54 path = tempfile.mkdtemp(dir=parent_dir) |
| 55 def DeleteDir(): |
| 56 # Don't use shutil.rmtree because it can't delete read-only files on Win. |
| 57 for root, dirs, files in os.walk(path, topdown=False): |
| 58 for name in files: |
| 59 filename = os.path.join(root, name) |
| 60 os.chmod(filename, stat.S_IWRITE) |
| 61 os.remove(filename) |
| 62 for name in dirs: |
| 63 os.rmdir(os.path.join(root, name)) |
| 64 atexit.register(DeleteDir) |
| 65 return path |
| 66 |
| 67 |
| 68 class InstallTest(unittest.TestCase): |
| 69 """Base updater test class. |
| 70 |
| 71 All dependencies, like Chrome installers and ChromeDriver, are downloaded at |
| 72 the beginning of the test. Dependencies are downloaded in the temp directory. |
| 73 This download occurs only once, before the first test is executed. Each test |
| 74 case starts an instance of ChromeDriver and terminates it upon completion. |
| 75 All updater tests should derive from this class. |
| 76 |
| 77 Example: |
| 78 |
| 79 class ProtectorUpdater(InstallTest): |
| 80 |
| 81 def testCanOpenGoogle(self): |
| 82 self._driver.get('http://www.google.com/') |
| 83 self.UpdateBuild() |
| 84 self._driver.get('http://www.msn.com/') |
| 85 |
| 86 Include the following in your updater test script to make it run standalone. |
| 87 |
| 88 from install_test import Main |
| 89 |
| 90 if __name__ == '__main__': |
| 91 Main() |
| 92 |
| 93 To fire off an updater test, use the command below. |
| 94 python test_script.py --url=<URL> --builds=22.0.1230.0,22.0.1231.0 |
| 95 """ |
| 96 |
| 97 _DIR_PREFIX = '__CHRBLD__' |
| 98 _INSTALLER_NAME = 'mini_installer.exe' |
| 99 _installer_paths = [] |
| 100 _chrome_driver = '' |
| 101 _installer_options = [] |
| 102 |
| 103 def __init__(self, methodName='runTest'): |
| 104 unittest.TestCase.__init__(self, methodName) |
| 105 self._counter = 0 |
| 106 current_version = chrome_installer_win.ChromeInstallation.GetCurrent() |
| 107 if current_version: |
| 108 current_version.Uninstall() |
| 109 self._install_type = ('system-level' in self._installer_options and |
| 110 chrome_installer_win.InstallationType.SYSTEM or |
| 111 chrome_installer_win.InstallationType.USER) |
| 112 |
| 113 def setUp(self): |
| 114 """Called before each unittest to prepare the test fixture.""" |
| 115 self._InstallNext() |
| 116 self._StartChromeDriver() |
| 117 |
| 118 def tearDown(self): |
| 119 """Called at the end of each unittest to do any test related cleanup.""" |
| 120 self._driver.quit() |
| 121 self._service.stop() |
| 122 self._installation.Uninstall() |
| 123 |
| 124 def _StartChromeDriver(self): |
| 125 """Starts ChromeDriver.""" |
| 126 self._service = service.Service(InstallTest._chrome_driver) |
| 127 self._service.start() |
| 128 self._driver = webdriver.Remote( |
| 129 self._service.service_url, |
| 130 {'chrome.binary' : self._installation.GetExePath()} |
| 131 |
| 132 def _InstallNext(self): |
| 133 """Helper method that installs Chrome.""" |
| 134 self._installation = chrome_installer_win.Install( |
| 135 self._installer_paths[self._counter], |
| 136 self._install_type, |
| 137 self._builds[self._counter], |
| 138 self._installer_options) |
| 139 self._counter += 1 |
| 140 |
| 141 def UpdateBuild(self): |
| 142 """Updates Chrome by installing a newer version.""" |
| 143 self._driver.quit() |
| 144 self._InstallNext() |
| 145 self._driver = webdriver.Remote(self._service.service_url, |
| 146 self._capabilities) |
| 147 |
| 148 @staticmethod |
| 149 def _Download(url, path): |
| 150 """Downloads a file from the specified URL. |
| 151 |
| 152 Args: |
| 153 url: URL where the file is located. |
| 154 path: Location where file will be downloaded. |
| 155 """ |
| 156 if not pyauto_utils.DoesUrlExist(url): |
| 157 raise RuntimeError('Either the URL or the file name is invalid.') |
| 158 urllib.urlretrieve(url, path) |
| 159 |
| 160 @staticmethod |
| 161 def InitTestFixture(builds, base_url, options): |
| 162 """Static method for passing command options to InstallTest. |
| 163 |
| 164 We do not instantiate InstallTest. Therefore, command arguments cannot |
| 165 be passed to its constructor. Since InstallTest needs to use these options |
| 166 and using globals is not an option, this method can be used by the Main |
| 167 class to pass the arguments it parses onto InstallTest. |
| 168 """ |
| 169 builds = builds.split(',') if builds else [] |
| 170 system = ({'Windows': 'win', |
| 171 'Darwin': 'mac', |
| 172 'Linux': 'linux'}).get(platform.system()) |
| 173 InstallTest._installer_options = options.split(',') if options else [] |
| 174 InstallTest._builds = builds |
| 175 tempdir = MakeTempDir() |
| 176 for build in builds: |
| 177 url = '%s%s/%s/mini_installer.exe' % (base_url, build, system) |
| 178 installer_path = os.path.join(tempdir, 'mini_installer_%s.exe' % build) |
| 179 InstallTest._installer_paths.append(installer_path) |
| 180 InstallTest._Download(url, installer_path) |
| 181 InstallTest._chrome_driver = os.path.join(tempdir, 'chromedriver.exe') |
| 182 url = '%s%s/%s/%s/chromedriver.exe' % (base_url, build, system, |
| 183 'chrome-win32.test') |
| 184 InstallTest._Download(url, InstallTest._chrome_driver) |
| 185 |
| 186 |
| 187 class Main(object): |
| 188 """Main program for running Updater tests.""" |
| 189 |
| 190 def __init__(self): |
| 191 self._SetLoggingConfiguration() |
| 192 self._ParseArgs() |
| 193 self._Run() |
| 194 |
| 195 def _ParseArgs(self): |
| 196 """Parses command line arguments.""" |
| 197 parser = optparse.OptionParser() |
| 198 parser.add_option( |
| 199 '-b', '--builds', type='string', default='', dest='builds', |
| 200 help='Specifies the two builds needed for testing.') |
| 201 parser.add_option( |
| 202 '-u', '--url', type='string', default='', dest='url', |
| 203 help='Specifies the build url, without the build number.') |
| 204 parser.add_option( |
| 205 '-o', '--options', type='string', default='', |
| 206 help='Specifies any additional Chrome options (i.e. --system-level).') |
| 207 opts, args = parser.parse_args() |
| 208 self._ValidateArgs(opts) |
| 209 InstallTest.InitTestFixture(opts.builds, opts.url, opts.options) |
| 210 |
| 211 def _ValidateArgs(self, opts): |
| 212 """Verifies the sanity of the command arguments. |
| 213 |
| 214 Confirms that all specified builds have a valid version number, and the |
| 215 build urls are valid. |
| 216 |
| 217 Args: |
| 218 opts: An object containing values for all command args. |
| 219 """ |
| 220 builds = opts.builds.split(',') |
| 221 for build in builds: |
| 222 if not re.match('\d+\.\d+\.\d+\.\d+', build): |
| 223 raise RuntimeError('Invalid build number: %s' % build) |
| 224 if not pyauto_utils.DoesUrlExist('%s/%s/' % (opts.url, build)): |
| 225 raise RuntimeError('Could not locate build no. %s' % build) |
| 226 |
| 227 def _SetLoggingConfiguration(self): |
| 228 """Sets the basic logging configuration.""" |
| 229 log_format = '%(asctime)s %(levelname)-8s %(message)s' |
| 230 logging.basicConfig(level=logging.INFO, format=log_format) |
| 231 |
| 232 def _GetTests(self): |
| 233 """Returns a list of unittests from the calling script.""" |
| 234 mod_name = [os.path.splitext(os.path.basename(sys.argv[0]))[0]] |
| 235 if os.path.dirname(sys.argv[0]) not in sys.path: |
| 236 sys.path.append(os.path.dirname(sys.argv[0])) |
| 237 return unittest.defaultTestLoader.loadTestsFromNames(mod_name) |
| 238 |
| 239 def _Run(self): |
| 240 """Runs the unit tests.""" |
| 241 tests = self._GetTests() |
| 242 result = pyauto_utils.GTestTextTestRunner(verbosity=1).run(tests) |
| 243 del(tests) |
| 244 if not result.wasSuccessful(): |
| 245 print >>sys.stderr, ('Not all tests were successful.') |
| 246 sys.exit(1) |
| 247 sys.exit(0) |
| OLD | NEW |