Chromium Code Reviews| Index: install_test/install_test.py |
| =================================================================== |
| --- install_test/install_test.py (revision 0) |
| +++ install_test/install_test.py (revision 0) |
| @@ -0,0 +1,261 @@ |
| +#!/usr/bin/env python |
| +# Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| +# Use of this source code is governed by a BSD-style license that can be |
| +# found in the LICENSE file. |
| + |
| +import optparse |
| +import os |
| +import platform |
| +import shutil |
| +import sys |
| +import tempfile |
| +import unittest |
| +import urllib |
| +import zipfile |
| + |
| +import chrome_checkout |
| + |
|
kkania
2012/06/14 17:20:33
no newline here, i think; check the style guide
nkang
2012/06/28 19:02:39
It's gone.
|
| +from chrome_installer import ChromeInstaller |
| + |
| +os.sys.path.append(os.path.join(os.path.pardir, 'pyautolib')) |
|
kkania
2012/06/14 17:20:33
os.sys? I thought it was just sys
nkang
2012/06/28 19:02:39
They are the same, but in order to use just sys, y
|
| +from fetch_prebuilt_pyauto import FetchPrebuilt |
| + |
| +# Global var. to hold pyautolib locations. A global is needed because pyautolib |
| +# files are downloaded only once at the beginning of the test. We cannot assign |
| +# these locations to a member var. because each unittest creates a new instance |
| +# of InstallTest, which means that while the first instance will know about the |
| +# locations, subsequent instances will not. So a global is used because it will |
| +# not go out of scope until the process exits. |
| +_DOWNLOAD_DIR = [] |
| +# Flag that determines if its the first instance, and downloads pyautolib and |
| +# other dependencies if it is. Its global for the same reason as above. |
| +_B_FIRST_TIME = True |
| + |
| +class InstallTest(unittest.TestCase): |
| + """Test fixture for tests involving installing/updating Chrome. |
| + |
| + Provides an interface to install or update chrome from within a testcase, and |
| + allows users to run pyauto tests using the installed version. User and system |
| + level installations are supported, and either one can be used for running the |
| + pyauto tests. Pyautolib files are downloaded at runtime and a PyUITest object |
| + is created when Chrome is installed or updated. Users can utilize that object |
| + to run updater tests. All Updater tests should derive from this class. |
| + """ |
| + |
| + def __init__(self, methodName='runTest'): |
| + global _B_FIRST_TIME |
| + unittest.TestCase.__init__(self, methodName) |
| + self._pyauto = None |
| + self._plat = self.GetPlatform() |
| + self._source_dirs = ['functional', 'pyautolib', 'pyftpdlib', 'selenium', |
| + 'simplejson', 'testserver', 'tlslite'] |
| + self._ParseArgs() |
| + self._dir_prefix = '__CHRBLD__' |
| + if self._builds: |
| + if _B_FIRST_TIME: |
| + for build in self._builds: |
| + if not self._DownloadDeps(build): |
| + print 'Couldn\'t download dependencies, aborting test...' |
| + sys.exit(-1) |
| + _B_FIRST_TIME = False |
| + |
| + def _ParseArgs(self): |
|
kkania
2012/06/14 17:20:33
move the global initialization stuff out to a main
nkang
2012/06/28 19:02:39
Done. Although, I hope you don't mind - since you
|
| + """Parses the command line arguments.""" |
| + parser = optparse.OptionParser() |
| + parser.add_option( |
| + '-b', '--builds', type='string', default='', dest='builds', |
| + help='Specifies the two (or more) builds needed for testing.') |
| + parser.add_option( |
| + '-u', '--url', type='string', default='', dest='url', |
| + help='Specifies the chrome-master2 url, without the build number.') |
| + parser.add_option( |
| + '-d', '--dir', type='string', default=os.getcwd(), |
| + help='Specifies directory where the installer will be downloaded.') |
| + parser.add_option( |
| + '-o', '--options', type='string', default='', |
| + help='Specifies any additional Chrome options (i.e. --system-level).') |
| + self.opts, self.args = parser.parse_args() |
| + self.dir = (lambda d: os.path.isdir(d) and d or os.getcwd())(self.opts.dir) |
| + self._builds = (lambda b: b.split(',') if b else [])(self.opts.builds) |
| + self._builds.sort() |
| + self._bld_counter = (lambda lst: 0 if len(lst) > 0 else None)(self._builds) |
|
kkania
2012/06/14 17:20:33
you use a bit too many abbreviations ('opts', 'bld
nkang
2012/06/28 19:02:39
Got rid of abbreviations wherever possible.
|
| + self._c_opts = ((lambda opts: opts.replace(',', ' ') if opts else '') |
| + (self.opts.options)) |
| + self._url = self.opts.url |
| + if self._url and not self._url.endswith('/'): |
| + self._url += '/' |
| + if self._builds: |
| + self._c_installer = ChromeInstaller(self._url, self._builds[0], |
| + dest=self.dir, opts=self._c_opts, |
| + clean=True) |
| + else: |
| + self._c_installer = None |
| + if not self._builds or not self._url: |
| + print 'Please specify a valid URL and at least two Chrome builds.' |
| + sys.exit(-1) |
| + |
| + def setUp(self): |
| + """Called before each unittest. It calls _Install, which installs the |
| + |
| + first Chrome build and creates a pyauto.PyUITest object. |
| + """ |
|
kkania
2012/06/14 17:20:33
i think we should uninstall first to make sure the
nkang
2012/06/28 19:02:39
Done, now if Chrome is already installed, we unins
|
| + self.InstallBuild() |
| + self.failIf(self._pyauto == None) |
| + |
| + def tearDown(self): |
| + """Called at the end of each unittest. Clears the modules registry so |
| + |
| + pyautolib can be reloaded when the build is updated. |
| + """ |
| + self._Refresh() |
| + self._DeleteBuild() |
| + |
| + def GetPlatform(self): |
| + """Returns the platform name.""" |
| + return ({'Windows': 'win', 'Darwin': 'mac', |
| + 'Linux': 'linux'}).get(platform.system()) |
| + |
| + def SetCurrentBuild(self, nVal): |
|
kkania
2012/06/14 17:20:33
check these, i don't think they're used
nkang
2012/06/28 19:02:39
Removed both of them.
|
| + """Sets current Chrome build.""" |
| + self._bld_counter = (lambda n: n if(n > 0 and n <= 2) else 0)(nVal) |
| + |
| + def GetCurrentBuild(self): |
| + """Returns the current chrome build.""" |
| + return self._builds[self._bld_counter] |
| + |
| + def _Refresh(self): |
| + """Deletes the PyUITest object and clears the modules registry.""" |
| + try: |
| + del(self._pyauto) |
| + except NameError, err: |
| + print 'CBaseUpdater._Refresh: ', err |
| + pass |
| + try: |
| + os.sys.modules.pop('pyauto') |
|
kkania
2012/06/14 17:20:33
i thought it was just sys.modules
nkang
2012/06/28 19:02:39
You can either call sys.modules or os.sys.modules,
|
| + os.sys.modules.pop('pyautolib') |
| + os.sys.modules.pop('_pyautolib') |
| + except KeyError, err: |
| + print 'CBaseUpdater._Refresh: ', err |
|
kkania
2012/06/14 17:20:33
when could this occur? I think we should just let
nkang
2012/06/28 19:02:39
This scenario, though unlikely, could occur if the
|
| + |
| + def _Install(self): |
| + """Installs chrome and creates a PyUITest object on completion.""" |
| + self._pyauto = None |
| + if isinstance(self._c_installer, ChromeInstaller): |
| + ret = self._c_installer.InstallChrome() |
| + if ret: |
| + try: |
| + import pyauto |
| + self._pyauto = pyauto.PyUITest(methodName='runTest', |
| + browser_path=os.path.dirname( |
| + ret.GetChromeExePath())) |
| + self._pyauto.suite_holder = pyauto.PyUITestSuite(['test.py']) |
| + self._pyauto.setUp() |
| + except ImportError, err: |
| + print 'CBaseUpdater.InstallBuild: ', err |
| + self._pyauto = None |
| + |
| + def InstallBuild(self): |
| + """Installs the first of the Chrome builds specified as command args.""" |
| + global _DOWNLOAD_DIR |
| + if _DOWNLOAD_DIR[1] in os.sys.path: |
|
kkania
2012/06/14 17:20:33
same here and many places in this file; i think al
nkang
2012/06/28 19:02:39
Done.
|
| + os.sys.path.remove(_DOWNLOAD_DIR[1]) |
| + if os.path.join(_DOWNLOAD_DIR[1], 'pyautolib') in os.sys.path: |
| + os.sys.path.remove(os.path.join(_DOWNLOAD_DIR, 'pyautolib')) |
| + os.sys.path.insert(0, _DOWNLOAD_DIR[0]) |
| + os.sys.path.insert(1, os.path.join(_DOWNLOAD_DIR[0], 'pyautolib')) |
| + self._bld_counter += 1 |
| + self._Install() |
| + |
| + def _Update(self): |
| + """Updates Chrome by installing the second(higher) version of Chrome.""" |
| + global _DOWNLOAD_DIR |
| + if _DOWNLOAD_DIR[0] in os.sys.path: |
| + os.sys.path.remove(_DOWNLOAD_DIR[0]) |
| + if os.path.join(_DOWNLOAD_DIR[0], 'pyautolib') in os.sys.path: |
| + os.sys.path.remove(os.path.join(_DOWNLOAD_DIR[0], 'pyautolib')) |
| + os.sys.path.insert(0, _DOWNLOAD_DIR[1]) |
| + os.sys.path.insert(1, os.path.join(_DOWNLOAD_DIR[1], 'pyautolib')) |
| + if self._bld_counter >= len(self._builds): |
| + print 'No more builds left to install. The following builds have '\ |
|
kkania
2012/06/14 17:20:33
raise, not print
nkang
2012/06/28 19:02:39
Done.
|
| + 'already been installed: %r' % self._builds |
| + return None |
| + if self._c_installer: |
| + self._c_installer.SetBuild(self._builds[self._bld_counter]) |
| + self._Install() |
| + |
| + def UpdateBuild(self): |
| + if self._pyauto: |
| + self._pyauto.TearDown() |
| + self._Refresh() |
| + self._Update() |
| + |
| + def _SrcFilesExist(self, root, items): |
| + """Checks if specified files/folders exist at specified 'root' folder. |
| + |
| + Args: |
| + root: Parent folder where all the source directories reside. |
| + items: List of files/folders to be verified for existence in the root. |
| + |
| + Returns: |
| + Boolean, True if all sub-folders exist in the root, otherwise False. |
| + """ |
| + return all(map(lambda p: os.path.exists(p) and True or False, |
| + [os.path.join(root, path) for path in items])) |
| + |
| + def _CheckoutSourceFiles(self, build, location): |
| + # Checkout folder doesn't exist or is missing some data. |
| + if(not os.path.isdir(location) or not |
| + self._SrcFilesExist(location, self._source_dirs)): |
| + return chrome_checkout.CheckOut(build, location) |
| + # Folder already exists, no need to do another checkout. |
| + else: |
| + return 0 |
| + |
| + def _DownloadDeps(self, build): |
| + global _DOWNLOAD_DIR |
| + ret = -1 |
| + url = '%s%s/%s' % (self._url, build, self._plat) |
| + download_dir = os.path.join('%s', '%s%s') % (tempfile.gettempdir(), |
| + self._dir_prefix, build) |
| + _DOWNLOAD_DIR.append(download_dir) |
| + if not os.path.isdir(download_dir): |
| + try: |
| + os.mkdir(download_dir) |
| + except(OSError, IOError), err: |
| + print 'InstallTest._DownloadDeps: %s' % err |
| + return False |
| + if not self._SrcFilesExist(download_dir, ['pyautolib.py', |
| + '_pyautolib.pyd']): |
| + fpb = FetchPrebuilt(url, download_dir, self._plat) |
| + if fpb.DoesUrlExist(url): |
| + ret = fpb.Run() |
| + else: |
| + ret = 0 |
| + # Check out source files. |
| + if ret == 0: |
| + self._CheckoutSourceFiles(build, download_dir) |
| + return True |
| + return False |
| + |
| + def _DeleteBuild(self): |
| + """Uninstalls Chrome""" |
| + if self._bld_counter == None or self._bld_counter < 0: |
| + return -1 |
| + cur_build = self._builds[self._bld_counter - 1] |
| + if cur_build != self._c_installer.GetBuild(): |
| + self._c_installer.SetBuild(cur_build) |
| + ret = self._c_installer.UninstallChrome() |
| + if ret: |
| + self._bld_counter = 0 |
| + return ret |
| + |
| + def _DeleteDepFiles(self): |
| + """Deletes Chrome related files that were downloaded for testing.""" |
| + global _DOWNLOAD_DIR |
| + for path in _DOWNLOAD_DIR: |
| + try: |
| + shutil.rmtree(path) |
| + except shutil.Error, err: |
| + print 'CBaseUpdater._DeleteDepFiles: ', err |
| + return -1 |
| + return 0 |
| Property changes on: install_test\install_test.py |
| ___________________________________________________________________ |
| Added: svn:eol-style |
| + LF |