| 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 import os |
| 7 import sys |
| 8 import optparse |
| 9 import platform |
| 10 import unittest |
| 11 import tempfile |
| 12 import urllib |
| 13 import shutil |
| 14 import zipfile |
| 15 |
| 16 from chrome_installer import ChromeInstaller |
| 17 from chrome_checkout import ChromeCheckout |
| 18 |
| 19 os.sys.path.append(os.path.join(os.path.pardir, 'pyautolib')) |
| 20 from fetch_prebuilt_pyauto import FetchPrebuilt |
| 21 |
| 22 # Global var. to hold pyautolib locations. A global is needed because pyautolib |
| 23 # files are downloaded only once at the beginning of the test. We cannot assign |
| 24 # these locations to a member var. because each unittest creates a new instance |
| 25 # of InstallTest, which means that while the first instance will know about the |
| 26 # locations, subsequent instances will not. So a global is used because it will |
| 27 # not go out of scope until the process exits. |
| 28 _DOWNLOAD_DIR = [] |
| 29 # Flag that determines if its the first instance, and downloads pyautolib and |
| 30 # other dependencies if it is. Its global for the same reason as above. |
| 31 _B_FIRST_TIME = True |
| 32 |
| 33 class InstallTest(unittest.TestCase): |
| 34 """Test fixture for tests involving installing/updating Chrome. |
| 35 |
| 36 Provides an interface to install or update chrome from within a testcase, and |
| 37 allows users to run pyauto tests using the installed version. User and system |
| 38 level installations are supported, and either one can be used for running the |
| 39 pyauto tests. Pyautolib files are downloaded at runtime and a PyUITest object |
| 40 is created when Chrome is installed or updated. Users can utilize that object |
| 41 to run updater tests. All Updater tests should derive from this class. |
| 42 """ |
| 43 |
| 44 def __init__(self, methodName='runTest'): |
| 45 global _B_FIRST_TIME |
| 46 unittest.TestCase.__init__(self, methodName) |
| 47 self._pyauto = None |
| 48 self._plat = self.GetPlatform() |
| 49 self._source_dirs = ['functional', 'pyautolib', 'pyftpdlib', 'selenium', |
| 50 'simplejson', 'testserver', 'tlslite'] |
| 51 self._ParseArgs() |
| 52 self._dir_prefix = '__CHRBLD__' |
| 53 if self._builds: |
| 54 if _B_FIRST_TIME: |
| 55 for build in self._builds: |
| 56 if not self._DownloadDeps(build): |
| 57 print 'Couldn\'t download dependencies, aborting test...' |
| 58 sys.exit(-1) |
| 59 _B_FIRST_TIME = False |
| 60 |
| 61 def _ParseArgs(self): |
| 62 """Parses the command line arguments.""" |
| 63 parser = optparse.OptionParser() |
| 64 parser.add_option( |
| 65 '-b', '--builds', type='string', default='', dest='builds', |
| 66 help='Specifies the two (or more) builds needed for testing.') |
| 67 parser.add_option( |
| 68 '-u', '--url', type='string', default='', dest='url', |
| 69 help='Specifies the chrome-master2 url, without the build number.') |
| 70 parser.add_option( |
| 71 '-d', '--dir', type='string', default=os.getcwd(), |
| 72 help='Specifies directory where the installer will be downloaded.') |
| 73 parser.add_option( |
| 74 '-o', '--options', type='string', default='', |
| 75 help='Specifies any additional Chrome options (i.e. --system-level).') |
| 76 self.opts, self.args = parser.parse_args() |
| 77 self.dir = (lambda d: os.path.isdir(d) and d or os.getcwd())(self.opts.dir) |
| 78 self._builds = (lambda b: b.split(',') if b else [])(self.opts.builds) |
| 79 self._builds.sort() |
| 80 self._bld_counter = (lambda lst: 0 if len(lst) > 0 else None)(self._builds)
|
| 81 self._c_opts = ((lambda opts: opts.replace(',', ' ') if opts else '') |
| 82 (self.opts.options)) |
| 83 self._url = self.opts.url |
| 84 if self._url and not self._url.endswith('/'): |
| 85 self._url += '/' |
| 86 if self._builds: |
| 87 self._c_installer = ChromeInstaller(self._url, self._builds[0], |
| 88 dest=self.dir, opts=self._c_opts, |
| 89 clean=True) |
| 90 else: |
| 91 self._c_installer = None |
| 92 if not self._builds or not self._url: |
| 93 print 'Please specify a valid URL and at least two Chrome builds.' |
| 94 sys.exit(-1) |
| 95 |
| 96 def setUp(self): |
| 97 """Called before each unittest. It calls _Install, which installs the |
| 98 |
| 99 first Chrome build and creates a pyauto.PyUITest object. |
| 100 """ |
| 101 self.InstallBuild() |
| 102 self.failIf(self._pyauto == None) |
| 103 |
| 104 def tearDown(self): |
| 105 """Called at the end of each unittest. Clears the modules registry so |
| 106 |
| 107 pyautolib can be reloaded when the build is updated. |
| 108 """ |
| 109 self._Refresh() |
| 110 self._DeleteBuild() |
| 111 |
| 112 def GetPlatform(self): |
| 113 """Returns the platform name.""" |
| 114 return ({'Windows': 'win', 'Darwin': 'mac', |
| 115 'Linux': 'linux'}).get(platform.system()) |
| 116 |
| 117 def SetCurrentBuild(self, nVal): |
| 118 """Sets current Chrome build.""" |
| 119 self._bld_counter = (lambda n: n if(n > 0 and n <= 2) else 0)(nVal) |
| 120 |
| 121 def GetCurrentBuild(self): |
| 122 """Returns the current chrome build.""" |
| 123 return self._builds[self._bld_counter] |
| 124 |
| 125 def _Refresh(self): |
| 126 """Deletes the PyUITest object and clears the modules registry.""" |
| 127 try: |
| 128 del(self._pyauto) |
| 129 except NameError, err: |
| 130 print 'CBaseUpdater._Refresh: ', err |
| 131 pass |
| 132 try: |
| 133 os.sys.modules.pop('pyauto') |
| 134 os.sys.modules.pop('pyautolib') |
| 135 os.sys.modules.pop('_pyautolib') |
| 136 except KeyError, err: |
| 137 print 'CBaseUpdater._Refresh: ', err |
| 138 |
| 139 def _Install(self): |
| 140 """Installs chrome and creates a PyUITest object on completion.""" |
| 141 self._pyauto = None |
| 142 if isinstance(self._c_installer, ChromeInstaller): |
| 143 ret = self._c_installer.InstallChrome() |
| 144 if ret: |
| 145 try: |
| 146 import pyauto |
| 147 self._pyauto = pyauto.PyUITest(methodName='runTest', |
| 148 browser_path=os.path.dirname( |
| 149 ret.GetChromeExePath())) |
| 150 self._pyauto.suite_holder = pyauto.PyUITestSuite(['test.py']) |
| 151 self._pyauto.setUp() |
| 152 except ImportError, err: |
| 153 print 'CBaseUpdater.InstallBuild: ', err |
| 154 self._pyauto = None |
| 155 |
| 156 def InstallBuild(self): |
| 157 """Installs the first of the Chrome builds specified as command args.""" |
| 158 global _DOWNLOAD_DIR |
| 159 if _DOWNLOAD_DIR[1] in os.sys.path: |
| 160 os.sys.path.remove(_DOWNLOAD_DIR[1]) |
| 161 if os.path.join(_DOWNLOAD_DIR[1], 'pyautolib') in os.sys.path: |
| 162 os.sys.path.remove(os.path.join(_DOWNLOAD_DIR, 'pyautolib')) |
| 163 os.sys.path.insert(0, _DOWNLOAD_DIR[0]) |
| 164 os.sys.path.insert(1, os.path.join(_DOWNLOAD_DIR[0], 'pyautolib')) |
| 165 self._bld_counter += 1 |
| 166 self._Install() |
| 167 |
| 168 def _Update(self): |
| 169 """Updates Chrome by installing the second(higher) version of Chrome.""" |
| 170 global _DOWNLOAD_DIR |
| 171 if _DOWNLOAD_DIR[0] in os.sys.path: |
| 172 os.sys.path.remove(_DOWNLOAD_DIR[0]) |
| 173 if os.path.join(_DOWNLOAD_DIR[0], 'pyautolib') in os.sys.path: |
| 174 os.sys.path.remove(os.path.join(_DOWNLOAD_DIR[0], 'pyautolib')) |
| 175 os.sys.path.insert(0, _DOWNLOAD_DIR[1]) |
| 176 os.sys.path.insert(1, os.path.join(_DOWNLOAD_DIR[1], 'pyautolib')) |
| 177 if self._bld_counter >= len(self._builds): |
| 178 print 'No more builds left to install. The following builds have '\ |
| 179 'already been installed: %r' % self._builds |
| 180 return None |
| 181 if self._c_installer: |
| 182 self._c_installer.SetBuild(self._builds[self._bld_counter]) |
| 183 self._Install() |
| 184 |
| 185 def UpdateBuild(self): |
| 186 if self._pyauto: |
| 187 self._pyauto.TearDown() |
| 188 self._Refresh() |
| 189 self._Update() |
| 190 |
| 191 def _SrcFilesExist(self, root, items): |
| 192 """Checks if specified files/folders exist at specified 'root' folder. |
| 193 |
| 194 Args: |
| 195 root: Parent folder where all the source directories reside. |
| 196 items: List of files/folders to be verified for existence in the root. |
| 197 |
| 198 Returns: |
| 199 Boolean, True if all sub-folders exist in the root, otherwise False. |
| 200 """ |
| 201 return all(map(lambda p: os.path.exists(p) and True or False, |
| 202 [os.path.join(root, path) for path in items])) |
| 203 |
| 204 def _CheckoutSourceFiles(self, build, location): |
| 205 # Checkout folder doesn't exist or is missing some data. |
| 206 if(not os.path.isdir(location) or not |
| 207 self._SrcFilesExist(location, self._source_dirs)): |
| 208 cc = ChromeCheckout(build, location) |
| 209 return cc.CheckOut() |
| 210 # Folder already exists, no need to do another checkout. |
| 211 else: |
| 212 return 0 |
| 213 |
| 214 def _DownloadDeps(self, build): |
| 215 global _DOWNLOAD_DIR |
| 216 ret = -1 |
| 217 url = '%s%s/%s' % (self._url, build, self._plat) |
| 218 download_dir = os.path.join('%s', '%s%s') % (tempfile.gettempdir(), |
| 219 self._dir_prefix, build) |
| 220 _DOWNLOAD_DIR.append(download_dir) |
| 221 if not os.path.isdir(download_dir): |
| 222 try: |
| 223 os.mkdir(download_dir) |
| 224 except(OSError, IOError), err: |
| 225 print 'InstallTest._DownloadDeps: %s' % err |
| 226 return False |
| 227 if not self._SrcFilesExist(download_dir, ['pyautolib.py', |
| 228 '_pyautolib.pyd']): |
| 229 fpb = FetchPrebuilt(url, download_dir, self._plat) |
| 230 if fpb.DoesUrlExist(url): |
| 231 ret = fpb.Run() |
| 232 else: |
| 233 ret = 0 |
| 234 # Check out source files. |
| 235 if ret == 0: |
| 236 return self._CheckoutSourceFiles(build, download_dir) == 0 |
| 237 return False |
| 238 |
| 239 def _DeleteBuild(self): |
| 240 """Uninstalls Chrome""" |
| 241 if self._bld_counter == None or self._bld_counter < 0: |
| 242 return -1 |
| 243 cur_build = self._builds[self._bld_counter - 1] |
| 244 if cur_build != self._c_installer.GetBuild(): |
| 245 self._c_installer.SetBuild(cur_build) |
| 246 ret = self._c_installer.UninstallChrome() |
| 247 if ret: |
| 248 self._bld_counter = 0 |
| 249 return ret |
| 250 |
| 251 def _DeleteDepFiles(self): |
| 252 """Deletes Chrome related files that were downloaded for testing.""" |
| 253 global _DOWNLOAD_DIR |
| 254 for path in _DOWNLOAD_DIR: |
| 255 try: |
| 256 shutil.rmtree(path) |
| 257 except shutil.Error, err: |
| 258 print 'CBaseUpdater._DeleteDepFiles: ', err |
| 259 return -1 |
| 260 return 0 |
| OLD | NEW |