~doanac/utah/bug1190775

« back to all changes in this revision

Viewing changes to utah/client/runner.py

  • Committer: Andy Doan
  • Date: 2013-06-11 15:54:54 UTC
  • mfrom: (931.1.3 utah-bzr)
  • Revision ID: andy.doan@canonical.com-20130611155454-06ek9b7w89c1c5i5
Finish the cleanup of the overly complex process_master_runlist function

Show diffs side-by-side

added added

removed removed

Lines of Context:
434
434
                self.result.status = 'PASS'
435
435
        return fetch_success
436
436
 
437
 
    def process_master_runlist(self, runlist=None, resume=False):
438
 
        """Parse a master runlist and build a list of suites from the data.
439
 
 
440
 
        :param runlist: URL pointing to a runlist
441
 
        :type rulist: string
442
 
        :param resume: Continue previous execution
443
 
        :type resume: boolean
444
 
        :returns: None
445
 
 
446
 
        """
447
 
        runlist = runlist or self.master_runlist
448
 
 
449
 
        # Download runlist using the URL passed through the commmand line to
450
 
        # local filename if needed (it might be a local file already or cached)
 
437
    @staticmethod
 
438
    def _fetch_and_parse(runlist):
451
439
        try:
452
440
            local_filename = urllib.urlretrieve(runlist)[0]
453
 
        except IOError:
454
 
            raise exceptions.MissingFile(runlist)
455
 
        except urllib.ContentTooShortError as err:
 
441
        except IOError as err:
456
442
            raise exceptions.MissingFile(
457
 
                'Error when downloading {} (probably interrupted): {}'
458
 
                .format(runlist, err))
 
443
                'Error when downloading {}: {}'.format(runlist, err))
459
444
 
460
445
        data = parse_yaml_file(local_filename)
461
 
        validator = DefaultValidator(self.MASTER_RUNLIST_SCHEMA)
 
446
        validator = DefaultValidator(Runner.MASTER_RUNLIST_SCHEMA)
462
447
        try:
463
448
            validator.validate(data)
464
449
        except jsonschema.ValidationError as exception:
466
451
                'Master runlist failed to validate: {!r}\n'
467
452
                'Detailed information: {}'
468
453
                .format(local_filename, exception))
 
454
        return data
 
455
 
 
456
    @staticmethod
 
457
    def _clean_suite(name):
 
458
        # convert to absolute name to make troubleshooting a little easier
 
459
        name = os.path.abspath(name)
 
460
        try:
 
461
            shutil.rmtree(name)
 
462
        except OSError as e:
 
463
            raise exceptions.UTAHClientError(
 
464
                'Error removing the testsuite {}: {}'.format(name, e))
 
465
 
 
466
    def _add_suite(self, suite):
 
467
        name = suite['name']
 
468
 
 
469
        if name not in self.fetched_suites:
 
470
            if self._fetch_suite(suite):
 
471
                self.fetched_suites.append(name)
 
472
                suite_runlist = suite.get('runlist', DEFAULT_TSLIST)
 
473
 
 
474
                s = TestSuite(name=name,
 
475
                              runlist_file=suite_runlist,
 
476
                              includes=suite.get('include_tests', None),
 
477
                              excludes=suite.get('exclude_tests', None),
 
478
                              result=self.result,
 
479
                              path=self.testsuitedir,
 
480
                              timeout=self.timeout,
 
481
                              battery_measurements=self.battery_measurements,
 
482
                              _save_state_callback=self.save_state,
 
483
                              _reboot_callback=self.reboot)
 
484
                self.add_suite(s)
 
485
            else:
 
486
                self.fetch_errors += 1
 
487
 
 
488
    def process_master_runlist(self, runlist=None, resume=False):
 
489
        """Parse a master runlist and build a list of suites from the data.
 
490
 
 
491
        :param runlist: URL pointing to a runlist
 
492
        :type rulist: string
 
493
        :param resume: Continue previous execution
 
494
        :type resume: boolean
 
495
 
 
496
        """
 
497
        runlist = runlist or self.master_runlist
 
498
        data = self._fetch_and_parse(runlist)
469
499
 
470
500
        if 'timeout' in data:
471
501
            self.timeout = int(data['timeout'])
472
502
 
473
 
        if 'name' in data:
474
 
            self.name = data['name']
475
 
        else:
476
 
            self.name = 'unnamed'
477
 
 
 
503
        self.name = data.get('name', 'unnamed')
478
504
        self.battery_measurements = data['battery_measurements']
479
505
        self.repeat_count = data['repeat_count']
480
506
 
482
508
 
483
509
        orig_dir = os.getcwd()
484
510
 
485
 
        if 'testsuites' in data:
486
 
            suites = data['testsuites']
487
 
        elif isinstance(data, list):
488
 
            suites = data
489
 
        else:
490
 
            raise exceptions.BadMasterRunlist(str(data))
491
 
 
 
511
        suites = data['testsuites']
492
512
        suites = data['testsuites'] if 'testsuites' in data else data
493
513
        for suite in suites:
494
514
            # Allow the inclusion of other master.run files
500
520
 
501
521
            name = suite['name']
502
522
 
503
 
            includes = suite.get('include_tests')
504
 
            excludes = suite.get('exclude_tests')
505
 
 
506
 
            suite_runlist = suite.get('runlist', DEFAULT_TSLIST)
507
 
 
508
523
            if name in seen:
509
524
                raise exceptions.BadMasterRunlist(
510
525
                    "{} duplicated in runlist".format(name))
512
527
            # Fetch the testsuite. On resume don't remove the testsuite
513
528
            # directory.
514
529
            if not resume and os.path.exists(name):
515
 
                # Using absolute name makes no difference
516
 
                # except on failures where it's easier
517
 
                # to find troubleshoot permission problems
518
 
                absolute_name = os.path.abspath(name)
519
 
                try:
520
 
                    shutil.rmtree(absolute_name)
521
 
                except OSError as err:
522
 
                    raise exceptions.UTAHClientError(
523
 
                        'Error removing the testsuite directory {}: {}'
524
 
                        .format(absolute_name, err))
 
530
                self._clean_suite(name)
 
531
 
525
532
            mkdir(name)
526
 
 
527
 
            if name not in self.fetched_suites:
528
 
                if not self._fetch_suite(suite):
529
 
                    # If fetch failed move on to the next testsuite.
530
 
                    self.fetch_errors += 1
531
 
                    continue
532
 
 
533
 
                self.fetched_suites.append(name)
534
 
 
535
 
                # Create a TestSuite
536
 
                s = TestSuite(name=name,
537
 
                              runlist_file=suite_runlist,
538
 
                              includes=includes,
539
 
                              excludes=excludes,
540
 
                              result=self.result,
541
 
                              path=self.testsuitedir,
542
 
                              timeout=self.timeout,
543
 
                              battery_measurements=self.battery_measurements,
544
 
                              _save_state_callback=self.save_state,
545
 
                              _reboot_callback=self.reboot)
546
 
                self.add_suite(s)
 
533
            self._add_suite(suite)
547
534
 
548
535
    def get_next_suite(self):
549
536
        """Return the next suite to be run.