testing/mochitest/runtestsb2g.py

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     1 # This Source Code Form is subject to the terms of the Mozilla Public
     2 # License, v. 2.0. If a copy of the MPL was not distributed with this file,
     3 # You can obtain one at http://mozilla.org/MPL/2.0/.
     5 import json
     6 import os
     7 import posixpath
     8 import shutil
     9 import sys
    10 import tempfile
    11 import threading
    12 import time
    13 import traceback
    15 here = os.path.abspath(os.path.dirname(__file__))
    16 sys.path.insert(0, here)
    18 from runtests import Mochitest
    19 from runtests import MochitestUtilsMixin
    20 from runtests import MochitestOptions
    21 from runtests import MochitestServer
    22 from mochitest_options import B2GOptions, MochitestOptions
    24 from marionette import Marionette
    26 from mozdevice import DeviceManagerADB
    27 from mozprofile import Profile, Preferences
    28 from mozrunner import B2GRunner
    29 import mozlog
    30 import mozinfo
    31 import moznetwork
    33 log = mozlog.getLogger('Mochitest')
    35 class B2GMochitest(MochitestUtilsMixin):
    36     def __init__(self, marionette,
    37                        out_of_process=True,
    38                        profile_data_dir=None,
    39                        locations=os.path.join(here, 'server-locations.txt')):
    40         super(B2GMochitest, self).__init__()
    41         self.marionette = marionette
    42         self.out_of_process = out_of_process
    43         self.locations_file = locations
    44         self.preferences = []
    45         self.webapps = None
    46         self.test_script = os.path.join(here, 'b2g_start_script.js')
    47         self.test_script_args = [self.out_of_process]
    48         self.product = 'b2g'
    50         if profile_data_dir:
    51             self.preferences = [os.path.join(profile_data_dir, f)
    52                                  for f in os.listdir(profile_data_dir) if f.startswith('pref')]
    53             self.webapps = [os.path.join(profile_data_dir, f)
    54                              for f in os.listdir(profile_data_dir) if f.startswith('webapp')]
    56         # mozinfo is populated by the parent class
    57         if mozinfo.info['debug']:
    58             self.SERVER_STARTUP_TIMEOUT = 180
    59         else:
    60             self.SERVER_STARTUP_TIMEOUT = 90
    62     def setup_common_options(self, options):
    63         test_url = self.buildTestPath(options)
    64         if len(self.urlOpts) > 0:
    65             test_url += "?" + "&".join(self.urlOpts)
    66         self.test_script_args.append(test_url)
    68     def buildTestPath(self, options):
    69         # Skip over the manifest building that happens on desktop.
    70         return self.buildTestURL(options)
    72     def build_profile(self, options):
    73         # preferences
    74         prefs = {}
    75         for path in self.preferences:
    76             prefs.update(Preferences.read_prefs(path))
    78         for v in options.extraPrefs:
    79             thispref = v.split("=", 1)
    80             if len(thispref) < 2:
    81                 print "Error: syntax error in --setpref=" + v
    82                 sys.exit(1)
    83             prefs[thispref[0]] = thispref[1]
    85         # interpolate the preferences
    86         interpolation = { "server": "%s:%s" % (options.webServer, options.httpPort),
    87                           "OOP": "true" if self.out_of_process else "false" }
    88         prefs = json.loads(json.dumps(prefs) % interpolation)
    89         for pref in prefs:
    90             prefs[pref] = Preferences.cast(prefs[pref])
    92         kwargs = {
    93             'addons': self.getExtensionsToInstall(options),
    94             'apps': self.webapps,
    95             'locations': self.locations_file,
    96             'preferences': prefs,
    97             'proxy': {"remote": options.webServer}
    98         }
   100         if options.profile:
   101             self.profile = Profile.clone(options.profile, **kwargs)
   102         else:
   103             self.profile = Profile(**kwargs)
   105         options.profilePath = self.profile.profile
   106         # TODO bug 839108 - mozprofile should probably handle this
   107         manifest = self.addChromeToProfile(options)
   108         self.copyExtraFilesToProfile(options)
   109         return manifest
   111     def run_tests(self, options):
   112         """ Prepare, configure, run tests and cleanup """
   114         self.leak_report_file = os.path.join(options.profilePath, "runtests_leaks.log")
   115         manifest = self.build_profile(options)
   117         self.startServers(options, None)
   118         self.buildURLOptions(options, {'MOZ_HIDE_RESULTS_TABLE': '1'})
   119         self.test_script_args.append(not options.emulator)
   120         self.test_script_args.append(options.wifi)
   122         if options.debugger or not options.autorun:
   123             timeout = None
   124         else:
   125             if not options.timeout:
   126                 if mozinfo.info['debug']:
   127                     options.timeout = 420
   128                 else:
   129                     options.timeout = 300
   130             timeout = options.timeout + 30.0
   132         log.info("runtestsb2g.py | Running tests: start.")
   133         status = 0
   134         try:
   135             runner_args = { 'profile': self.profile,
   136                             'devicemanager': self._dm,
   137                             'marionette': self.marionette,
   138                             'remote_test_root': self.remote_test_root,
   139                             'symbols_path': options.symbolsPath,
   140                             'test_script': self.test_script,
   141                             'test_script_args': self.test_script_args }
   142             self.runner = B2GRunner(**runner_args)
   143             self.runner.start(outputTimeout=timeout)
   144             status = self.runner.wait()
   145             if status is None:
   146                 # the runner has timed out
   147                 status = 124
   148         except KeyboardInterrupt:
   149             log.info("runtests.py | Received keyboard interrupt.\n");
   150             status = -1
   151         except:
   152             traceback.print_exc()
   153             log.error("Automation Error: Received unexpected exception while running application\n")
   154             self.runner.check_for_crashes()
   155             status = 1
   157         self.stopServers()
   159         log.info("runtestsb2g.py | Running tests: end.")
   161         if manifest is not None:
   162             self.cleanup(manifest, options)
   163         return status
   166 class B2GDeviceMochitest(B2GMochitest):
   168     _dm = None
   170     def __init__(self, marionette, devicemanager, profile_data_dir,
   171                  local_binary_dir, remote_test_root=None, remote_log_file=None):
   172         B2GMochitest.__init__(self, marionette, out_of_process=True, profile_data_dir=profile_data_dir)
   173         self._dm = devicemanager
   174         self.remote_test_root = remote_test_root or self._dm.getDeviceRoot()
   175         self.remote_profile = posixpath.join(self.remote_test_root, 'profile')
   176         self.remote_log = remote_log_file or posixpath.join(self.remote_test_root, 'log', 'mochitest.log')
   177         self.local_log = None
   178         self.local_binary_dir = local_binary_dir
   180         if not self._dm.dirExists(posixpath.dirname(self.remote_log)):
   181             self._dm.mkDirs(self.remote_log)
   183     def cleanup(self, manifest, options):
   184         if self.local_log:
   185             self._dm.getFile(self.remote_log, self.local_log)
   186             self._dm.removeFile(self.remote_log)
   188         if options.pidFile != "":
   189             try:
   190                 os.remove(options.pidFile)
   191                 os.remove(options.pidFile + ".xpcshell.pid")
   192             except:
   193                 print "Warning: cleaning up pidfile '%s' was unsuccessful from the test harness" % options.pidFile
   195         # stop and clean up the runner
   196         if getattr(self, 'runner', False):
   197             self.runner.cleanup()
   198             self.runner = None
   200     def startServers(self, options, debuggerInfo):
   201         """ Create the servers on the host and start them up """
   202         savedXre = options.xrePath
   203         savedUtility = options.utilityPath
   204         savedProfie = options.profilePath
   205         options.xrePath = self.local_binary_dir
   206         options.utilityPath = self.local_binary_dir
   207         options.profilePath = tempfile.mkdtemp()
   209         MochitestUtilsMixin.startServers(self, options, debuggerInfo)
   211         options.xrePath = savedXre
   212         options.utilityPath = savedUtility
   213         options.profilePath = savedProfie
   215     def buildURLOptions(self, options, env):
   216         self.local_log = options.logFile
   217         options.logFile = self.remote_log
   218         options.profilePath = self.profile.profile
   219         retVal = super(B2GDeviceMochitest, self).buildURLOptions(options, env)
   221         self.setup_common_options(options)
   223         options.profilePath = self.remote_profile
   224         options.logFile = self.local_log
   225         return retVal
   228 class B2GDesktopMochitest(B2GMochitest, Mochitest):
   230     def __init__(self, marionette, profile_data_dir):
   231         B2GMochitest.__init__(self, marionette, out_of_process=False, profile_data_dir=profile_data_dir)
   232         Mochitest.__init__(self)
   233         self.certdbNew = True
   235     def runMarionetteScript(self, marionette, test_script, test_script_args):
   236         assert(marionette.wait_for_port())
   237         marionette.start_session()
   238         marionette.set_context(marionette.CONTEXT_CHROME)
   240         if os.path.isfile(test_script):
   241             f = open(test_script, 'r')
   242             test_script = f.read()
   243             f.close()
   244         self.marionette.execute_script(test_script,
   245                                        script_args=test_script_args)
   247     def startTests(self):
   248         # This is run in a separate thread because otherwise, the app's
   249         # stdout buffer gets filled (which gets drained only after this
   250         # function returns, by waitForFinish), which causes the app to hang.
   251         thread = threading.Thread(target=self.runMarionetteScript,
   252                                   args=(self.marionette,
   253                                         self.test_script,
   254                                         self.test_script_args))
   255         thread.start()
   257     def buildURLOptions(self, options, env):
   258         retVal = super(B2GDesktopMochitest, self).buildURLOptions(options, env)
   260         self.setup_common_options(options)
   262         # Copy the extensions to the B2G bundles dir.
   263         extensionDir = os.path.join(options.profilePath, 'extensions', 'staged')
   264         bundlesDir = os.path.join(os.path.dirname(options.app),
   265                                   'distribution', 'bundles')
   267         for filename in os.listdir(extensionDir):
   268             shutil.rmtree(os.path.join(bundlesDir, filename), True)
   269             shutil.copytree(os.path.join(extensionDir, filename),
   270                             os.path.join(bundlesDir, filename))
   272         return retVal
   274     def buildProfile(self, options):
   275         return self.build_profile(options)
   278 def run_remote_mochitests(parser, options):
   279     # create our Marionette instance
   280     kwargs = {}
   281     if options.emulator:
   282         kwargs['emulator'] = options.emulator
   283         if options.noWindow:
   284             kwargs['noWindow'] = True
   285         if options.geckoPath:
   286             kwargs['gecko_path'] = options.geckoPath
   287         if options.logcat_dir:
   288             kwargs['logcat_dir'] = options.logcat_dir
   289         if options.busybox:
   290             kwargs['busybox'] = options.busybox
   291         if options.symbolsPath:
   292             kwargs['symbols_path'] = options.symbolsPath
   293     # needless to say sdcard is only valid if using an emulator
   294     if options.sdcard:
   295         kwargs['sdcard'] = options.sdcard
   296     if options.b2gPath:
   297         kwargs['homedir'] = options.b2gPath
   298     if options.marionette:
   299         host, port = options.marionette.split(':')
   300         kwargs['host'] = host
   301         kwargs['port'] = int(port)
   303     marionette = Marionette.getMarionetteOrExit(**kwargs)
   305     if options.emulator:
   306         dm = marionette.emulator.dm
   307     else:
   308         # create the DeviceManager
   309         kwargs = {'adbPath': options.adbPath,
   310                   'deviceRoot': options.remoteTestRoot}
   311         if options.deviceIP:
   312             kwargs.update({'host': options.deviceIP,
   313                            'port': options.devicePort})
   314         dm = DeviceManagerADB(**kwargs)
   316     options = parser.verifyRemoteOptions(options)
   317     if (options == None):
   318         print "ERROR: Invalid options specified, use --help for a list of valid options"
   319         sys.exit(1)
   321     mochitest = B2GDeviceMochitest(marionette, dm, options.profile_data_dir, options.xrePath,
   322                                    remote_test_root=options.remoteTestRoot,
   323                                    remote_log_file=options.remoteLogFile)
   325     options = parser.verifyOptions(options, mochitest)
   326     if (options == None):
   327         sys.exit(1)
   329     retVal = 1
   330     try:
   331         mochitest.cleanup(None, options)
   332         retVal = mochitest.run_tests(options)
   333     except:
   334         print "Automation Error: Exception caught while running tests"
   335         traceback.print_exc()
   336         mochitest.stopServers()
   337         try:
   338             mochitest.cleanup(None, options)
   339         except:
   340             pass
   341         retVal = 1
   343     sys.exit(retVal)
   345 def run_desktop_mochitests(parser, options):
   346     # create our Marionette instance
   347     kwargs = {}
   348     if options.marionette:
   349         host, port = options.marionette.split(':')
   350         kwargs['host'] = host
   351         kwargs['port'] = int(port)
   352     marionette = Marionette.getMarionetteOrExit(**kwargs)
   353     mochitest = B2GDesktopMochitest(marionette, options.profile_data_dir)
   355     # add a -bin suffix if b2g-bin exists, but just b2g was specified
   356     if options.app[-4:] != '-bin':
   357         if os.path.isfile("%s-bin" % options.app):
   358             options.app = "%s-bin" % options.app
   360     options = MochitestOptions.verifyOptions(parser, options, mochitest)
   361     if options == None:
   362         sys.exit(1)
   364     if options.desktop and not options.profile:
   365         raise Exception("must specify --profile when specifying --desktop")
   367     options.browserArgs += ['-marionette']
   369     sys.exit(mochitest.runTests(options, onLaunch=mochitest.startTests))
   371 def main():
   372     parser = B2GOptions()
   373     options, args = parser.parse_args()
   375     if options.desktop:
   376         run_desktop_mochitests(parser, options)
   377     else:
   378         run_remote_mochitests(parser, options)
   380 if __name__ == "__main__":
   381     main()

mercurial