def mock_control_file_parsing(self):
     """Fake out find_and_parse_tests(), returning content from |self.files|.
     """
     for test in self.files.values():
         test.text = test.string  # mimic parsing.
     self.mox.StubOutWithMock(Suite, 'find_and_parse_tests')
     Suite.find_and_parse_tests(mox.IgnoreArg(),
                                mox.IgnoreArg(),
                                mox.IgnoreArg(),
                                add_experimental=True,
                                forgiving_parser=True,
                                run_prod_code=False).AndReturn(
                                    self.files.values())
    def testFindSuiteSyntaxErrors(self):
        """Check all control files for syntax errors.

        This test actually parses all control files in the autotest directory
        for syntax errors, by using the un-forgiving parser and pretending to
        look for all control files with the suite attribute.
        """
        autodir = os.path.abspath(
            os.path.join(os.path.dirname(__file__), '..', '..', '..'))
        fs_getter = Suite.create_fs_getter(autodir)
        predicate = lambda t: hasattr(t, 'suite')
        Suite.find_and_parse_tests(fs_getter,
                                   predicate,
                                   add_experimental=True,
                                   forgiving_parser=False)
Beispiel #3
0
    def testSuiteDependencies(self):
        """Should add suite dependencies to tests scheduled."""
        name_list = [
            'name-data_one', 'name-data_two', 'name-data_three',
            'name-data_four', 'name-data_five', 'name-data_six',
            'name-data_seven'
        ]
        keyval_dict = {
            constants.SCHEDULED_TEST_COUNT_KEY: len(name_list),
            constants.SCHEDULED_TEST_NAMES_KEY: repr(name_list)
        }

        self.mock_control_file_parsing()
        recorder = self.mox.CreateMock(base_job.base_job)
        self.expect_job_scheduling(recorder, suite_deps=['extra'])
        self.mox.StubOutWithMock(utils, 'write_keyval')
        utils.write_keyval(None, keyval_dict)

        self.mox.ReplayAll()
        suite = Suite.create_from_name(self._TAG,
                                       self._BUILDS,
                                       self._BOARD,
                                       self.devserver,
                                       extra_deps=['extra'],
                                       afe=self.afe,
                                       tko=self.tko)
        suite.schedule(recorder.record_entry)
Beispiel #4
0
def _perform_reimage_and_run(spec, afe, tko, suite_job_id=None):
    """
    Do the work of reimaging hosts and running tests.

    @param spec: a populated _SuiteSpec object.
    @param afe: an instance of AFE as defined in server/frontend.py.
    @param tko: an instance of TKO as defined in server/frontend.py.
    @param suite_job_id: Job id that will act as parent id to all sub jobs.
                         Default: None
    """
    suite = Suite.create_from_predicates(
        predicates=[spec.predicate],
        name=spec.name,
        builds=spec.builds,
        board=spec.board,
        devserver=spec.devserver,
        afe=afe,
        tko=tko,
        pool=spec.pool,
        results_dir=spec.job.resultdir,
        max_runtime_mins=spec.max_runtime_mins,
        timeout_mins=spec.timeout_mins,
        file_bugs=spec.file_bugs,
        suite_job_id=suite_job_id,
        extra_deps=spec.suite_dependencies,
        priority=spec.priority,
        wait_for_results=spec.wait_for_results,
        job_retry=spec.job_retry,
        max_retries=spec.max_retries,
        offload_failures_only=spec.offload_failures_only,
        test_source_build=spec.test_source_build,
        run_prod_code=spec.run_prod_code,
        job_keyvals=spec.job_keyvals,
        test_args=spec.test_args)
    _run_suite_with_spec(suite, spec)
Beispiel #5
0
    def testRetryMapAfterScheduling(self):
        """Test job-test and test-job mapping are correctly updated."""
        name_list = ['name-data_one', 'name-data_two', 'name-data_three',
                     'name-data_four', 'name-data_five', 'name-data_six',
                     'name-data_seven']
        keyval_dict = {constants.SCHEDULED_TEST_COUNT_KEY: 7,
                       constants.SCHEDULED_TEST_NAMES_KEY: repr(name_list)}

        self.mock_control_file_parsing()
        recorder = self.mox.CreateMock(base_job.base_job)
        self.expect_job_scheduling(recorder)
        self.mox.StubOutWithMock(utils, 'write_keyval')
        utils.write_keyval(None, keyval_dict)

        all_files = self.files.items()
        # Sort tests in self.files so that they are in the same
        # order as they are scheduled.
        expected_retry_map = {}
        for n in range(len(all_files)):
            test = all_files[n][1]
            job_id = n + 1
            job_retries = 1 if test.job_retries is None else test.job_retries
            if job_retries > 0:
                expected_retry_map[job_id] = {
                        'state': RetryHandler.States.NOT_ATTEMPTED,
                        'retry_max': job_retries}

        self.mox.ReplayAll()
        suite = Suite.create_from_name(self._TAG, self._BUILDS, self._BOARD,
                                       self.devserver,
                                       afe=self.afe, tko=self.tko,
                                       job_retry=True)
        suite.schedule(recorder.record_entry)

        self.assertEqual(expected_retry_map, suite._retry_handler._retry_map)
Beispiel #6
0
    def testInheritedKeyvals(self):
        """Tests should inherit some whitelisted job keyvals."""
        # Only keyvals in constants.INHERITED_KEYVALS are inherited to tests.
        job_keyvals = {
            constants.KEYVAL_CIDB_BUILD_ID: '111',
            constants.KEYVAL_CIDB_BUILD_STAGE_ID: '222',
            'your': 'name',
        }
        test_keyvals = {
            constants.KEYVAL_CIDB_BUILD_ID: '111',
            constants.KEYVAL_CIDB_BUILD_STAGE_ID: '222',
        }

        self.mock_control_file_parsing()
        recorder = self.mox.CreateMock(base_job.base_job)
        self.expect_job_scheduling(
            recorder,
            extra_keyvals=test_keyvals)
        self.mox.StubOutWithMock(utils, 'write_keyval')
        utils.write_keyval(None, job_keyvals)
        utils.write_keyval(None, mox.IgnoreArg())

        self.mox.ReplayAll()
        suite = Suite.create_from_name(self._TAG, self._BUILDS, self._BOARD,
                                       self.devserver,
                                       afe=self.afe, tko=self.tko,
                                       job_keyvals=job_keyvals)
        suite.schedule(recorder.record_entry)
    def _init_test_source_build(self, test_source_build):
        """Initialize test_source_build attribute."""
        if test_source_build:
            test_source_build = self.devserver.translate(test_source_build)

        self.test_source_build = Suite.get_test_source_build(
                self.builds, test_source_build=test_source_build)
Beispiel #8
0
    def testScheduleTestsAndRecord(self):
        """Should schedule stable and experimental tests with the AFE."""
        name_list = [
            'name-data_one', 'name-data_two', 'name-data_three',
            'name-data_four', 'name-data_five', 'name-data_six',
            'name-data_seven'
        ]
        keyval_dict = {
            constants.SCHEDULED_TEST_COUNT_KEY: 7,
            constants.SCHEDULED_TEST_NAMES_KEY: repr(name_list)
        }

        self.mock_control_file_parsing()
        self.mox.ReplayAll()
        suite = Suite.create_from_name(self._TAG,
                                       self._BUILDS,
                                       self._BOARD,
                                       self.devserver,
                                       afe=self.afe,
                                       tko=self.tko,
                                       results_dir=self.tmpdir)
        self.mox.ResetAll()
        recorder = self.mox.CreateMock(base_job.base_job)
        self.expect_job_scheduling(recorder, suite=suite)

        self.mox.StubOutWithMock(utils, 'write_keyval')
        utils.write_keyval(self.tmpdir, keyval_dict)
        self.mox.ReplayAll()
        suite.schedule(recorder.record_entry)
        for job in suite._jobs:
            self.assertTrue(hasattr(job, 'test_name'))
Beispiel #9
0
    def testSuiteMaxRetries(self):
        """Test suite max retries."""
        name_list = [
            'name-data_one', 'name-data_two', 'name-data_three',
            'name-data_four', 'name-data_five', 'name-data_six',
            'name-data_seven'
        ]
        keyval_dict = {
            constants.SCHEDULED_TEST_COUNT_KEY: 7,
            constants.SCHEDULED_TEST_NAMES_KEY: repr(name_list)
        }

        self.mock_control_file_parsing()
        recorder = self.mox.CreateMock(base_job.base_job)
        self.expect_job_scheduling(recorder)
        self.mox.StubOutWithMock(utils, 'write_keyval')
        utils.write_keyval(None, keyval_dict)
        self.mox.ReplayAll()
        suite = Suite.create_from_name(self._TAG,
                                       self._BUILDS,
                                       self._BOARD,
                                       self.devserver,
                                       afe=self.afe,
                                       tko=self.tko,
                                       job_retry=True,
                                       max_retries=1)
        suite.schedule(recorder.record_entry)
        self.assertEqual(suite._retry_handler._max_retries, 1)
        # Find the job_id of the test that allows retry
        job_id = suite._retry_handler._retry_map.iterkeys().next()
        suite._retry_handler.add_retry(old_job_id=job_id, new_job_id=10)
        self.assertEqual(suite._retry_handler._max_retries, 0)
Beispiel #10
0
    def testReimageAndSIGTERM(self):
        """Should reimage_and_run that causes a SIGTERM and fails cleanly."""
        def suicide(*_, **__):
            """Send SIGTERM to current process to exit.

            @param _: Ignored.
            @param __: Ignored.
            """
            os.kill(os.getpid(), signal.SIGTERM)

        # Mox doesn't play well with SIGTERM, but it does play well with
        # with exceptions, so here we're using an exception to simulate
        # execution being interrupted by a signal.
        class UnhandledSIGTERM(Exception):
            """Exception to be raised when SIGTERM is received."""
            pass

        def handler(signal_number, frame):
            """Handler for receiving a signal.

            @param signal_number: signal number.
            @param frame: stack frame object.
            """
            raise UnhandledSIGTERM()

        signal.signal(signal.SIGTERM, handler)
        spec = mock.MagicMock()
        spec.builds = self._BUILDS
        spec.test_source_build = Suite.get_test_source_build(self._BUILDS)
        spec.devserver.stage_artifacts.side_effect = suicide
        spec.run_prod_code = False

        self.assertRaises(UnhandledSIGTERM,
                          dynamic_suite._perform_reimage_and_run, spec, None,
                          None, None)
 def testRetryMapAfterScheduling(self):
     """Test job-test and test-job mapping are correctly updated."""
     self.mock_control_file_parsing()
     recorder = self.mox.CreateMock(base_job.base_job)
     self.expect_job_scheduling(recorder, add_experimental=True)
     self.mox.ReplayAll()
     suite = Suite.create_from_name(self._TAG,
                                    self._BUILDS,
                                    self._BOARD,
                                    self.devserver,
                                    afe=self.afe,
                                    tko=self.tko,
                                    job_retry=True)
     suite.schedule(recorder.record_entry, add_experimental=True)
     all_files = self.files.items()
     # Sort tests in self.files so that they are in the same
     # order as they are scheduled.
     all_files.sort(key=lambda record: record[1].experimental)
     expected_retry_map = {}
     for n in range(len(all_files)):
         test = all_files[n][1]
         job_id = n + 1
         if test.job_retries > 0:
             expected_retry_map[job_id] = {
                 'state': RetryHandler.States.NOT_ATTEMPTED,
                 'retry_max': test.job_retries
             }
     self.assertEqual(expected_retry_map, suite._retry_handler._retry_map)
    def testFindAndParseTestsAttr(self):
        """Should find all tests that match a predicate."""
        self.expect_control_file_parsing()
        self.mox.ReplayAll()

        predicate = Suite.matches_attribute_expression_predicate('attr:attr')
        tests = Suite.find_and_parse_tests(self.getter,
                                           predicate,
                                           self._TAG,
                                           add_experimental=True)
        self.assertEquals(len(tests), 6)
        self.assertTrue(self.files['one'] in tests)
        self.assertTrue(self.files['two'] in tests)
        self.assertTrue(self.files['three'] in tests)
        self.assertTrue(self.files['four'] in tests)
        self.assertTrue(self.files['six'] in tests)
        self.assertTrue(self.files['seven'] in tests)
    def testFindAndParseStableTests(self):
        """Should find only non-experimental tests that match a predicate."""
        self.expect_control_file_parsing()
        self.mox.ReplayAll()

        predicate = lambda d: d.text == self.files['two'].string
        tests = Suite.find_and_parse_tests(self.getter, predicate, self._TAG)
        self.assertEquals(len(tests), 1)
        self.assertEquals(tests[0], self.files['two'])
Beispiel #14
0
def main():
    """main script."""
    # Parse filepath from cmd line.
    parser = argparse.ArgumentParser(description='Create attribute whitelist.')
    parser.add_argument('path',
                        metavar='WHITELIST_FILE_PATH',
                        help='Path to the file whitelist is written to. E.g. '
                        './attribute_whitelist.txt')
    args = parser.parse_args()

    # Get all the suites from current test control files, and order them.
    fs_getter = Suite.create_fs_getter(common.autotest_dir)
    devserver = dev_server.ImageServer('')
    suite_list = Suite.list_all_suites('', devserver, fs_getter)
    suite_list.sort(key=str.lower)

    # Parse attributes from suites, and write to a file
    whitelist = ['suite:' + x for x in suite_list]
    _WriteToFile(whitelist, args.path)
    def testAdHocSuiteCreation(self):
        """Should be able to schedule an ad-hoc suite by specifying
        a single test name."""
        self.expect_control_file_parsing(suite_name='ad_hoc_suite')
        self.mox.ReplayAll()
        predicate = Suite.test_name_equals_predicate('name-data_five')
        suite = Suite.create_from_predicates([predicate],
                                             self._BUILDS,
                                             self._BOARD,
                                             devserver=None,
                                             cf_getter=self.getter,
                                             afe=self.afe,
                                             tko=self.tko)

        self.assertFalse(self.files['one'] in suite.tests)
        self.assertFalse(self.files['two'] in suite.tests)
        self.assertFalse(self.files['one'] in suite.unstable_tests())
        self.assertFalse(self.files['two'] in suite.stable_tests())
        self.assertFalse(self.files['one'] in suite.stable_tests())
        self.assertFalse(self.files['two'] in suite.unstable_tests())
        self.assertFalse(self.files['four'] in suite.tests)
        self.assertTrue(self.files['five'] in suite.tests)
def main():
    """Entry point to run the suite enumerator command."""
    parser, options, args = parse_options()
    if options.listall:
        if args:
            print 'Cannot use suite_name with --listall'
            parser.print_help()
    elif not args or len(args) != 1:
        parser.print_help()
        return

    fs_getter = Suite.create_fs_getter(options.autotest_dir)
    devserver = dev_server.ImageServer('')
    if options.listall:
        for suite in Suite.list_all_suites('', devserver, fs_getter):
            print suite
        return

    suite = Suite.create_from_name(args[0], {}, '', devserver, fs_getter)
    # If in test list, print firmware_FAFTSetup before other tests
    # NOTE: the test.name value can be *different* from the directory
    # name that appears in test.path
    PRETEST_LIST = [
        'firmware_FAFTSetup',
    ]
    for test in filter(lambda test: test.name in \
                              PRETEST_LIST, suite.stable_tests()):
        print test.path
    for test in filter(lambda test: test.name not in \
                       PRETEST_LIST, suite.stable_tests()):
        print test.path

    # Check if test_suites/control.suite_name exists.
    control_path = os.path.join(options.autotest_dir, 'test_suites',
                                'control.' + args[0])
    if not os.path.exists(control_path):
        print >> sys.stderr, ('Warning! control file is missing: %s' %
                              control_path)
    def testScheduleStableTests(self):
        """Should schedule only stable tests with the AFE."""
        self.mock_control_file_parsing()
        recorder = self.mox.CreateMock(base_job.base_job)
        self.expect_job_scheduling(recorder, add_experimental=False)

        self.mox.ReplayAll()
        suite = Suite.create_from_name(self._TAG,
                                       self._BUILDS,
                                       self._BOARD,
                                       self.devserver,
                                       afe=self.afe,
                                       tko=self.tko)
        suite.schedule(recorder.record_entry, add_experimental=False)
 def testScheduleUnrunnableTestsTESTNA(self):
     """Tests which fail to schedule should be TEST_NA."""
     self.mock_control_file_parsing()
     recorder = self.mox.CreateMock(base_job.base_job)
     self.expect_job_scheduling(recorder,
                                add_experimental=True,
                                raises=True)
     self.mox.ReplayAll()
     suite = Suite.create_from_name(self._TAG,
                                    self._BUILDS,
                                    self._BOARD,
                                    self.devserver,
                                    afe=self.afe,
                                    tko=self.tko)
     suite.schedule(recorder.record_entry, add_experimental=True)
 def testGetTestsSortedByTime(self):
     """Should find all tests and sorted by TIME setting."""
     self.expect_control_file_parsing()
     self.mox.ReplayAll()
     # Get all tests.
     tests = Suite.find_and_parse_tests(self.getter,
                                        lambda d: True,
                                        self._TAG,
                                        add_experimental=True)
     self.assertEquals(len(tests), 7)
     times = [
         control_data.ControlData.get_test_time_index(test.time)
         for test in tests
     ]
     self.assertTrue(all(x >= y for x, y in zip(times, times[1:])),
                     'Tests are not ordered correctly.')
    def testFindAndParseTestsSuite(self):
        """Should find all tests that match a predicate."""
        self.expect_control_file_parsing()
        self.mox.ReplayAll()

        predicate = lambda d: d.suite == self._TAG
        tests = Suite.find_and_parse_tests(self.getter,
                                           predicate,
                                           self._TAG,
                                           add_experimental=True)
        self.assertEquals(len(tests), 6)
        self.assertTrue(self.files['one'] in tests)
        self.assertTrue(self.files['two'] in tests)
        self.assertTrue(self.files['three'] in tests)
        self.assertTrue(self.files['five'] in tests)
        self.assertTrue(self.files['six'] in tests)
        self.assertTrue(self.files['seven'] in tests)
    def testSuiteDependencies(self):
        """Should add suite dependencies to tests scheduled."""
        self.mock_control_file_parsing()
        recorder = self.mox.CreateMock(base_job.base_job)
        self.expect_job_scheduling(recorder,
                                   add_experimental=False,
                                   suite_deps=['extra'])

        self.mox.ReplayAll()
        suite = Suite.create_from_name(self._TAG,
                                       self._BUILDS,
                                       self._BOARD,
                                       self.devserver,
                                       extra_deps=['extra'],
                                       afe=self.afe,
                                       tko=self.tko)
        suite.schedule(recorder.record_entry, add_experimental=False)
def main(argv):
    """main scripts to seed attributes in test control files.

  Args:
    @param argv: Command line arguments including `sys.argv[0]`.
  """
    # Parse execution cmd
    parser = argparse.ArgumentParser(
        description='Seed ATTRIBUTES in test control files.')
    parser.add_argument('--execute',
                        action='store_true',
                        default=False,
                        help='Execute the script to seed attributes in all '
                        'test control files.')
    args = parser.parse_args(argv)

    # When execute is True, run the script to seed attributes in control files.
    if args.execute:
        # Get the whitelist path, hardcode the path currently
        path_whitelist = os.path.join(common.autotest_dir,
                                      'site_utils/attribute_whitelist.txt')

        # Go through all control file, check whether attribute matches suite. Return
        # a changelist which contains the paths to the control files not match.
        fs_getter = Suite.create_fs_getter(common.autotest_dir)
        changelist = AttrSuiteMatch(fs_getter.get_control_file_list(),
                                    path_whitelist)
        count = len(changelist)

        logging.info('Starting to seed attributes in %d control files...' %
                     count)
        # Modify attributes based on suite for the control files not match.
        for path in changelist:
            logging.info('Seeding ATTRIBUTES in %s' % path)
            count = count - 1
            logging.info('%d files remaining...' % count)
            SeedAttributes(path)

        logging.info('Finished seeding attributes.')

    # When not specify 'execute' in cmd, not modify control files.
    else:
        logging.info(
            'No files are modified. To seed attributes in control files, '
            'please add \'--execute\' argument when run the script.')
Beispiel #23
0
    def testScheduleUnrunnableTestsTESTNA(self):
        """Tests which fail to schedule should be TEST_NA."""
        # Since all tests will be fail to schedule, the num of scheduled tests
        # will be zero.
        name_list = []
        keyval_dict = {constants.SCHEDULED_TEST_COUNT_KEY: 0,
                       constants.SCHEDULED_TEST_NAMES_KEY: repr(name_list)}

        self.mock_control_file_parsing()
        recorder = self.mox.CreateMock(base_job.base_job)
        self.expect_job_scheduling(recorder, raises=True)
        self.mox.StubOutWithMock(utils, 'write_keyval')
        utils.write_keyval(None, keyval_dict)
        self.mox.ReplayAll()
        suite = Suite.create_from_name(self._TAG, self._BUILDS, self._BOARD,
                                       self.devserver,
                                       afe=self.afe, tko=self.tko)
        suite.schedule(recorder.record_entry)
    def _createSuiteWithMockedTestsAndControlFiles(self, file_bugs=False):
        """Create a Suite, using mocked tests and control file contents.

        @return Suite object, after mocking out behavior needed to create it.
        """
        self.expect_control_file_parsing()
        self.mox.ReplayAll()
        suite = Suite.create_from_name(self._TAG,
                                       self._BUILDS,
                                       self._BOARD,
                                       self.devserver,
                                       self.getter,
                                       afe=self.afe,
                                       tko=self.tko,
                                       file_bugs=file_bugs,
                                       job_retry=True)
        self.mox.ResetAll()
        return suite
 def testSuiteMaxRetries(self):
     self.mock_control_file_parsing()
     recorder = self.mox.CreateMock(base_job.base_job)
     self.expect_job_scheduling(recorder, add_experimental=True)
     self.mox.ReplayAll()
     suite = Suite.create_from_name(self._TAG,
                                    self._BUILDS,
                                    self._BOARD,
                                    self.devserver,
                                    afe=self.afe,
                                    tko=self.tko,
                                    job_retry=True,
                                    max_retries=1)
     suite.schedule(recorder.record_entry, add_experimental=True)
     self.assertEqual(suite._retry_handler._max_retries, 1)
     # Find the job_id of the test that allows retry
     job_id = suite._retry_handler._retry_map.iterkeys().next()
     suite._retry_handler.add_retry(old_job_id=job_id, new_job_id=10)
     self.assertEqual(suite._retry_handler._max_retries, 0)
 def testScheduleTestsAndRecord(self):
     """Should schedule stable and experimental tests with the AFE."""
     self.mock_control_file_parsing()
     self.mox.ReplayAll()
     suite = Suite.create_from_name(self._TAG,
                                    self._BUILDS,
                                    self._BOARD,
                                    self.devserver,
                                    afe=self.afe,
                                    tko=self.tko,
                                    results_dir=self.tmpdir)
     self.mox.ResetAll()
     recorder = self.mox.CreateMock(base_job.base_job)
     self.expect_job_scheduling(recorder,
                                add_experimental=True,
                                suite=suite)
     self.mox.ReplayAll()
     suite.schedule(recorder.record_entry, True)
     for job in suite._jobs:
         self.assertTrue(hasattr(job, 'test_name'))
    def testStableUnstableFilter(self):
        """Should distinguish between experimental and stable tests."""
        self.expect_control_file_parsing()
        self.mox.ReplayAll()
        suite = Suite.create_from_name(self._TAG,
                                       self._BUILDS,
                                       self._BOARD,
                                       devserver=None,
                                       cf_getter=self.getter,
                                       afe=self.afe,
                                       tko=self.tko)

        self.assertTrue(self.files['one'] in suite.tests)
        self.assertTrue(self.files['two'] in suite.tests)
        self.assertTrue(self.files['one'] in suite.unstable_tests())
        self.assertTrue(self.files['two'] in suite.stable_tests())
        self.assertFalse(self.files['one'] in suite.stable_tests())
        self.assertFalse(self.files['two'] in suite.unstable_tests())
        # Sanity check.
        self.assertFalse(self.files['four'] in suite.tests)
Beispiel #28
0
    def testReimageAndSIGTERM(self):
        """Should reimage_and_run that causes a SIGTERM and fails cleanly."""
        def suicide(*_, **__):
            """Send SIGTERM to current process to exit.

            @param _: Ignored.
            @param __: Ignored.
            """
            os.kill(os.getpid(), signal.SIGTERM)

        # Mox doesn't play well with SIGTERM, but it does play well with
        # with exceptions, so here we're using an exception to simulate
        # execution being interrupted by a signal.
        class UnhandledSIGTERM(Exception):
            """Exception to be raised when SIGTERM is received."""
            pass

        def handler(signal_number, frame):
            """Handler for receiving a signal.

            @param signal_number: signal number.
            @param frame: stack frame object.
            """
            raise UnhandledSIGTERM()

        signal.signal(signal.SIGTERM, handler)
        spec = self.mox.CreateMock(dynamic_suite.SuiteSpec)
        spec.builds = self._BUILDS
        spec.test_source_build = Suite.get_test_source_build(self._BUILDS)
        spec.devserver = self.mox.CreateMock(dev_server.ImageServer)
        spec.devserver.stage_artifacts(
            image=spec.builds[provision.CROS_VERSION_PREFIX],
            artifacts=['control_files',
                       'test_suites']).WithSideEffects(suicide)
        spec.run_prod_code = False

        self.mox.ReplayAll()

        self.assertRaises(UnhandledSIGTERM,
                          dynamic_suite._perform_reimage_and_run, spec, None,
                          None, None)
Beispiel #29
0
def create_suite_job(name='',
                     board='',
                     build='',
                     pool='',
                     control_file='',
                     check_hosts=True,
                     num=None,
                     file_bugs=False,
                     timeout=24,
                     timeout_mins=None,
                     priority=priorities.Priority.DEFAULT,
                     suite_args=None,
                     wait_for_results=True,
                     job_retry=False,
                     max_retries=None,
                     max_runtime_mins=None,
                     suite_min_duts=0,
                     offload_failures_only=False,
                     builds={},
                     test_source_build=None,
                     run_prod_code=False,
                     **kwargs):
    """
    Create a job to run a test suite on the given device with the given image.

    When the timeout specified in the control file is reached, the
    job is guaranteed to have completed and results will be available.

    @param name: The test name if control_file is supplied, otherwise the name
                 of the test suite to run, e.g. 'bvt'.
    @param board: the kind of device to run the tests on.
    @param build: unique name by which to refer to the image from now on.
    @param builds: the builds to install e.g.
                   {'cros-version:': 'x86-alex-release/R18-1655.0.0',
                    'fw-version:':  'x86-alex-firmware/R36-5771.50.0',
                    'fwro-version:':  'x86-alex-firmware/R36-5771.49.0'}
                   If builds is given a value, it overrides argument build.
    @param test_source_build: Build that contains the server-side test code.
    @param pool: Specify the pool of machines to use for scheduling
            purposes.
    @param check_hosts: require appropriate live hosts to exist in the lab.
    @param num: Specify the number of machines to schedule across (integer).
                Leave unspecified or use None to use default sharding factor.
    @param file_bugs: File a bug on each test failure in this suite.
    @param timeout: The max lifetime of this suite, in hours.
    @param timeout_mins: The max lifetime of this suite, in minutes. Takes
                         priority over timeout.
    @param priority: Integer denoting priority. Higher is more important.
    @param suite_args: Optional arguments which will be parsed by the suite
                       control file. Used by control.test_that_wrapper to
                       determine which tests to run.
    @param wait_for_results: Set to False to run the suite job without waiting
                             for test jobs to finish. Default is True.
    @param job_retry: Set to True to enable job-level retry. Default is False.
    @param max_retries: Integer, maximum job retries allowed at suite level.
                        None for no max.
    @param max_runtime_mins: Maximum amount of time a job can be running in
                             minutes.
    @param suite_min_duts: Integer. Scheduler will prioritize getting the
                           minimum number of machines for the suite when it is
                           competing with another suite that has a higher
                           priority but already got minimum machines it needs.
    @param offload_failures_only: Only enable gs_offloading for failed jobs.
    @param run_prod_code: If True, the suite will run the test code that
                          lives in prod aka the test code currently on the
                          lab servers. If False, the control files and test
                          code for this suite run will be retrieved from the
                          build artifacts.
    @param kwargs: extra keyword args. NOT USED.

    @raises ControlFileNotFound: if a unique suite control file doesn't exist.
    @raises NoControlFileList: if we can't list the control files at all.
    @raises StageControlFileFailure: If the dev server throws 500 while
                                     staging test_suites.
    @raises ControlFileEmpty: if the control file exists on the server, but
                              can't be read.

    @return: the job ID of the suite; -1 on error.
    """
    if type(num) is not int and num is not None:
        raise error.SuiteArgumentException('Ill specified num argument %r. '
                                           'Must be an integer or None.' % num)
    if num == 0:
        logging.warning("Can't run on 0 hosts; using default.")
        num = None

    # TODO(dshi): crbug.com/496782 Remove argument build and its reference after
    # R45 falls out of stable channel.
    if build and not builds:
        builds = {provision.CROS_VERSION_PREFIX: build}
    # TODO(dshi): crbug.com/497236 Remove this check after firmware ro provision
    # is supported in Autotest.
    if provision.FW_RO_VERSION_PREFIX in builds:
        raise error.SuiteArgumentException(
            'Updating RO firmware is not supported yet.')
    # Default test source build to CrOS build if it's not specified.
    test_source_build = Suite.get_test_source_build(
        builds, test_source_build=test_source_build)

    suite_name = canonicalize_suite_name(name)
    if run_prod_code:
        ds = dev_server.ImageServer.resolve(build)
        keyvals = {}
        getter = control_file_getter.FileSystemGetter([
            _CONFIG.get_config_value('SCHEDULER',
                                     'drone_installation_directory')
        ])
        control_file = getter.get_control_file_contents_by_name(suite_name)
    else:
        (ds, keyvals) = _stage_build_artifacts(test_source_build)
    keyvals[constants.SUITE_MIN_DUTS_KEY] = suite_min_duts

    if not control_file:
        # No control file was supplied so look it up from the build artifacts.
        suite_name = canonicalize_suite_name(name)
        control_file = _get_control_file_contents_by_name(
            test_source_build, ds, suite_name)
        # Do not change this naming convention without updating
        # site_utils.parse_job_name.
        name = '%s-%s' % (test_source_build, suite_name)

    timeout_mins = timeout_mins or timeout * 60
    max_runtime_mins = max_runtime_mins or timeout * 60

    if not board:
        board = utils.ParseBuildName(builds[provision.CROS_VERSION_PREFIX])[0]

    # TODO(dshi): crbug.com/496782 Remove argument build and its reference after
    # R45 falls out of stable channel.
    # Prepend build and board to the control file.
    inject_dict = {
        'board': board,
        'build': builds.get(provision.CROS_VERSION_PREFIX),
        'builds': builds,
        'check_hosts': check_hosts,
        'pool': pool,
        'num': num,
        'file_bugs': file_bugs,
        'timeout': timeout,
        'timeout_mins': timeout_mins,
        'devserver_url': ds.url(),
        'priority': priority,
        'suite_args': suite_args,
        'wait_for_results': wait_for_results,
        'job_retry': job_retry,
        'max_retries': max_retries,
        'max_runtime_mins': max_runtime_mins,
        'offload_failures_only': offload_failures_only,
        'test_source_build': test_source_build,
        'run_prod_code': run_prod_code
    }

    control_file = tools.inject_vars(inject_dict, control_file)

    return rpc_utils.create_job_common(name,
                                       priority=priority,
                                       timeout_mins=timeout_mins,
                                       max_runtime_mins=max_runtime_mins,
                                       control_type='Server',
                                       control_file=control_file,
                                       hostless=True,
                                       keyvals=keyvals)
Beispiel #30
0
def _perform_reimage_and_run(spec, afe, tko, predicate, suite_job_id=None):
    """
    Do the work of reimaging hosts and running tests.

    @param spec: a populated SuiteSpec object.
    @param afe: an instance of AFE as defined in server/frontend.py.
    @param tko: an instance of TKO as defined in server/frontend.py.
    @param predicate: A function mapping ControlData objects to True if they
                      should be included in the suite.
    @param suite_job_id: Job id that will act as parent id to all sub jobs.
                         Default: None
    """
    # We can't do anything else until the devserver has finished downloading
    # control_files and test_suites packages so that we can get the control
    # files we should schedule.
    try:
        if not spec.run_prod_code:
            spec.devserver.stage_artifacts(spec.test_source_build,
                                           ['control_files', 'test_suites'])
    except dev_server.DevServerException as e:
        # If we can't get the control files, there's nothing to run.
        raise error.AsynchronousBuildFailure(e)

    timestamp = datetime.datetime.now().strftime(time_utils.TIME_FMT)
    utils.write_keyval(spec.job.resultdir,
                       {constants.ARTIFACT_FINISHED_TIME: timestamp})

    suite = Suite.create_from_predicates(
        predicates=[predicate],
        name=spec.name,
        builds=spec.builds,
        board=spec.board,
        devserver=spec.devserver,
        afe=afe,
        tko=tko,
        pool=spec.pool,
        results_dir=spec.job.resultdir,
        max_runtime_mins=spec.max_runtime_mins,
        timeout_mins=spec.timeout_mins,
        file_bugs=spec.file_bugs,
        file_experimental_bugs=spec.file_experimental_bugs,
        suite_job_id=suite_job_id,
        extra_deps=spec.suite_dependencies,
        priority=spec.priority,
        wait_for_results=spec.wait_for_results,
        job_retry=spec.job_retry,
        max_retries=spec.max_retries,
        offload_failures_only=spec.offload_failures_only,
        test_source_build=spec.test_source_build,
        run_prod_code=spec.run_prod_code)

    # Now we get to asychronously schedule tests.
    suite.schedule(spec.job.record_entry, spec.add_experimental)

    if suite.wait_for_results:
        logging.debug('Waiting on suite.')
        suite.wait(spec.job.record_entry, spec.bug_template)
        logging.debug('Finished waiting on suite. '
                      'Returning from _perform_reimage_and_run.')
    else:
        logging.info('wait_for_results is set to False, suite job will exit '
                     'without waiting for test jobs to finish.')