コード例 #1
0
ファイル: worker.py プロジェクト: zhanghaihua/autophone
    def phone_disconnected(self, msg_body):
        """Indicate that a phone has become unreachable or experienced a
        error from which we might be able to recover."""
        if self.has_error():
            return
        self.loggerdeco.info('Phone disconnected: %s.' % msg_body)
        if msg_body and self.mailer:
            self.loggerdeco.info('Sending notification...')
            try:
                self.mailer.send(
                    'Phone %s disconnected' % self.phone_cfg['phoneid'],
                    '''Hello, this is Autophone. Phone %s appears to be disconnected:

%s

I'll keep trying to ping it periodically in case it reappears.
''' % (self.phone_cfg['phoneid'], msg_body))
                self.loggerdeco.info('Sent.')
            except socket.error:
                self.loggerdeco.exception('Failed to send disconnected-phone '
                                          'notification.')
        self.status_update(
            phonetest.PhoneTestMessage(
                self.phone_cfg['phoneid'],
                phonetest.PhoneTestMessage.DISCONNECTED))
コード例 #2
0
ファイル: worker.py プロジェクト: zhanghaihua/autophone
    def run(self):
        sys.stdout = file(self.outfile, 'a', 0)
        sys.stderr = sys.stdout
        self.filehandler = MultiprocessingTimedRotatingFileHandler(
            self.logfile, when='midnight', backupCount=7)
        fileformatstring = ('%(asctime)s|%(levelname)s' '|%(message)s')
        self.fileformatter = logging.Formatter(fileformatstring)
        self.filehandler.setFormatter(self.fileformatter)
        self.logger.addHandler(self.filehandler)

        self.loggerdeco.info('PhoneWorker starting up.')

        DroidSUT.loglevel = self.user_cfg.get('debug', 3)

        for t in self.tests:
            t.status_cb = self.status_update

        self.status_update(
            phonetest.PhoneTestMessage(self.phone_cfg['phoneid'], self.status))

        if self.status != phonetest.PhoneTestMessage.DISABLED:
            if not self.check_sdcard():
                self.recover_phone()
            if self.has_error():
                self.loggerdeco.error('Initial SD card check failed.')

        self.main_loop()
コード例 #3
0
ファイル: worker.py プロジェクト: zhanghaihua/autophone
 def handle_cmd(self, request):
     if not request:
         self.loggerdeco.debug('handle_cmd: No request')
         pass
     elif request[0] == 'stop':
         self.loggerdeco.info('Stopping at user\'s request...')
         self._stop = True
     elif request[0] == 'job':
         # This is just a notification that breaks us from waiting on the
         # command queue; it's not essential, since jobs are stored in
         # a db, but it allows the worker to react quickly to a request if
         # it isn't doing anything else.
         self.loggerdeco.debug('Received job command request...')
         pass
     elif request[0] == 'reboot':
         self.loggerdeco.info('Rebooting at user\'s request...')
         self.reboot()
     elif request[0] == 'disable':
         self.disable_phone('Disabled at user\'s request', False)
     elif request[0] == 'enable':
         self.loggerdeco.info('Enabling phone at user\'s request...')
         if self.has_error():
             self.status_update(
                 phonetest.PhoneTestMessage(self.phone_cfg['phoneid'],
                                            phonetest.PhoneTestMessage.IDLE,
                                            self.current_build))
             self.last_ping = None
     elif request[0] == 'debug':
         self.loggerdeco.info(
             'Setting debug level %d at user\'s request...' % request[1])
         self.user_cfg['debug'] = request[1]
         DroidSUT.debug = self.user_cfg['debug']
         # update any existing DroidSUT objects
         if self._dm:
             self._dm.loglevel = self.user_cfg['debug']
         for t in self.tests:
             t.set_dm_debug(self.user_cfg['debug'])
     elif request[0] == 'ping':
         self.loggerdeco.info('Pinging at user\'s request...')
         self.ping()
     else:
         self.loggerdeco.debug('handle_cmd: Unknown request %s' %
                               request[0])
コード例 #4
0
ファイル: worker.py プロジェクト: zhanghaihua/autophone
 def handle_timeout(self):
     if (self.status != phonetest.PhoneTestMessage.DISABLED and
         (not self.last_ping or
          (datetime.datetime.now() - self.last_ping > datetime.timedelta(
              seconds=self.user_cfg[PHONE_PING_INTERVAL])))):
         self.last_ping = datetime.datetime.now()
         if self.ping():
             if self.status == phonetest.PhoneTestMessage.DISCONNECTED:
                 self.recover_phone()
             if not self.has_error():
                 self.status_update(
                     phonetest.PhoneTestMessage(
                         self.phone_cfg['phoneid'],
                         phonetest.PhoneTestMessage.IDLE,
                         self.current_build))
         else:
             self.loggerdeco.info('Ping unanswered.')
             # No point in trying to recover, since we couldn't
             # even perform a simple action.
             if not self.has_error():
                 self.phone_disconnected('No response to ping.')
コード例 #5
0
ファイル: worker.py プロジェクト: zhanghaihua/autophone
    def check_sdcard(self):
        self.loggerdeco.info('Checking SD card.')
        success = True
        try:
            dev_root = self.dm.getDeviceRoot()
            if dev_root:
                d = posixpath.join(dev_root, 'autophonetest')
                self.dm.removeDir(d)
                self.dm.mkDir(d)
                if self.dm.dirExists(d):
                    with tempfile.NamedTemporaryFile() as tmp:
                        tmp.write('autophone test\n')
                        tmp.flush()
                        self.dm.pushFile(tmp.name,
                                         posixpath.join(d, 'sdcard_check'))
                    self.dm.removeDir(d)
                else:
                    self.loggerdeco.error('Failed to create directory under '
                                          'device root!')
                    success = False
            else:
                self.loggerdeco.error('Invalid device root.')
                success = False
        except DMError:
            self.loggerdeco.exception('Exception while checking SD card!')
            success = False

        if not success:
            # FIXME: Should this be called under more circumstances than just
            # checking the SD card?
            self.clear_test_base_paths()
            return False

        # reset status if there had previous been an error.
        # FIXME: should send email that phone is back up.
        self.status_update(
            phonetest.PhoneTestMessage(self.phone_cfg['phoneid'],
                                       phonetest.PhoneTestMessage.IDLE))
        return True
コード例 #6
0
ファイル: worker.py プロジェクト: zhanghaihua/autophone
    def disable_phone(self, errmsg, send_email=True):
        """Completely disable phone. No further attempts to recover it will
        be performed unless initiated by the user."""
        self.loggerdeco.info('Disabling phone: %s.' % errmsg)
        if errmsg and send_email and self.mailer:
            self.loggerdeco.info('Sending notification...')
            try:
                self.mailer.send(
                    'Phone %s disabled' % self.phone_cfg['phoneid'],
                    '''Hello, this is Autophone. Phone %s has been disabled:

%s

I gave up on it. Sorry about that. You can manually re-enable it with
the "enable" command.
''' % (self.phone_cfg['phoneid'], errmsg))
                self.loggerdeco.info('Sent.')
            except socket.error:
                self.loggerdeco.exception('Failed to send disabled-phone '
                                          'notification.')
        self.status_update(
            phonetest.PhoneTestMessage(self.phone_cfg['phoneid'],
                                       phonetest.PhoneTestMessage.DISABLED,
                                       msg=errmsg))
コード例 #7
0
ファイル: worker.py プロジェクト: zhanghaihua/autophone
 def handle_job(self, job):
     phoneid = self.phone_cfg['phoneid']
     abi = self.phone_cfg['abi']
     build_url = job['build_url']
     self.loggerdeco.debug('handle_job: job: %s, abi: %s' % (job, abi))
     incompatible_job = False
     if abi == 'x86':
         if 'x86' not in build_url:
             incompatible_job = True
     elif abi == 'armeabi-v6':
         if 'armv6' not in build_url:
             incompatible_job = True
     else:
         if 'x86' in build_url or 'armv6' in build_url:
             incompatible_job = True
     if incompatible_job:
         self.loggerdeco.debug('Ignoring incompatible job %s '
                               'for phone abi %s' % (build_url, abi))
         self.jobs.job_completed(job['id'])
         return
     # Determine if we will test this build and if we need
     # to enable unittests.
     skip_build = True
     enable_unittests = False
     for test in self.tests:
         test_devices_repos = test.test_devices_repos
         if not test_devices_repos:
             # We know we will test this build, but not yet
             # if any of the other tests enable_unittests.
             skip_build = False
         elif not phoneid in test_devices_repos:
             # This device will not run this test.
             pass
         else:
             for repo in test_devices_repos[phoneid]:
                 if repo in build_url:
                     skip_build = False
                     enable_unittests = test.enable_unittests
                     break
         if not skip_build:
             break
     if skip_build:
         self.loggerdeco.debug('Ignoring job %s ' % build_url)
         self.jobs.job_completed(job['id'])
         return
     self.loggerdeco.info('Checking job %s.' % build_url)
     client = buildserver.BuildCacheClient(port=self.build_cache_port)
     self.loggerdeco.info('Fetching build...')
     cache_response = client.get(build_url,
                                 enable_unittests=enable_unittests)
     client.close()
     if not cache_response['success']:
         self.loggerdeco.warning('Errors occured getting build %s: %s' %
                                 (build_url, cache_response['error']))
         return
     self.loggerdeco.info('Starting job %s.' % build_url)
     starttime = datetime.datetime.now()
     if self.run_tests(cache_response['metadata']):
         self.loggerdeco.info('Job completed.')
         self.jobs.job_completed(job['id'])
         self.status_update(
             phonetest.PhoneTestMessage(self.phone_cfg['phoneid'],
                                        phonetest.PhoneTestMessage.IDLE,
                                        self.current_build))
     else:
         self.loggerdeco.error('Job failed.')
     stoptime = datetime.datetime.now()
     self.loggerdeco.info('Job elapsed time: %s' % (stoptime - starttime))
コード例 #8
0
ファイル: worker.py プロジェクト: zhanghaihua/autophone
    def run_tests(self, build_metadata):
        if not self.has_error():
            self.loggerdeco.info('Rebooting...')
            self.reboot()

        # may have gotten an error trying to reboot, so test again
        if self.has_error():
            self.loggerdeco.info('Phone is in error state; not running test.')
            return False

        repo = build_metadata['tree']
        build_date = datetime.datetime.fromtimestamp(
            float(build_metadata['blddate']))

        self.status_update(
            phonetest.PhoneTestMessage(self.phone_cfg['phoneid'],
                                       phonetest.PhoneTestMessage.INSTALLING,
                                       build_metadata['blddate']))
        self.loggerdeco.info('Installing build %s.' % build_date)

        success = False
        for attempt in range(self.user_cfg[PHONE_RETRY_LIMIT]):
            try:
                pathOnDevice = posixpath.join(self.dm.getDeviceRoot(),
                                              'build.apk')
                self.dm.pushFile(
                    os.path.join(build_metadata['cache_build_dir'],
                                 'build.apk'), pathOnDevice)
                self.dm.installApp(pathOnDevice)
                self.dm.removeFile(pathOnDevice)
                success = True
            except DMError:
                exc = 'Exception installing fennec attempt %d!\n\n%s' % (
                    attempt, traceback.format_exc())
                self.loggerdeco.exception(
                    'Exception installing fennec attempt %d!' % attempt)
                time.sleep(self.user_cfg[PHONE_RETRY_WAIT])
        if not success:
            self.phone_disconnected(exc)
            return False
        self.current_build = build_metadata['blddate']

        self.loggerdeco.info('Running tests...')
        for t in self.tests:
            if self.has_error():
                break
            try:
                repos = t.test_devices_repos[self.phone_cfg['phoneid']]
                if repos and repo not in repos:
                    self.loggerdeco.debug('run_tests: ignoring build %s '
                                          'repo %s not in '
                                          'defined repos: %s' %
                                          (build_date, repo, repos))
                    continue
            except KeyError:
                pass

            t.current_build = build_metadata['blddate']
            try:
                t.runjob(build_metadata, self)
            except DMError:
                exc = 'Uncaught device error while running test!\n\n%s' % \
                    traceback.format_exc()
                self.loggerdeco.exception('Uncaught device error while '
                                          'running test!')
                self.phone_disconnected(exc)
                return False
        return True
コード例 #9
0
ファイル: worker.py プロジェクト: zhanghaihua/autophone
 def reboot(self):
     self.status_update(
         phonetest.PhoneTestMessage(self.phone_cfg['phoneid'],
                                    phonetest.PhoneTestMessage.REBOOTING))
     self.recover_phone()