| #!/usr/bin/python | |
| # Copyright 2015 The Chromium OS Authors. All rights reserved. | |
| # Use of this source code is governed by a BSD-style license that can be | |
| # found in the LICENSE file. | |
| # pylint: disable-msg=C0111 | |
| import os, unittest | |
| import mox | |
| import common | |
| import subprocess | |
| import types | |
| from autotest_lib.server import utils | |
| from autotest_lib.server.cros.dynamic_suite import constants | |
| from autotest_lib.site_utils import test_runner_utils | |
| class StartsWithList(mox.Comparator): | |
| def __init__(self, start_of_list): | |
| """Mox comparator which returns True if the argument | |
| to the mocked function is a list that begins with the elements | |
| in start_of_list. | |
| """ | |
| self._lhs = start_of_list | |
| def equals(self, rhs): | |
| if len(rhs)<len(self._lhs): | |
| return False | |
| for (x, y) in zip(self._lhs, rhs): | |
| if x != y: | |
| return False | |
| return True | |
| class ContainsSublist(mox.Comparator): | |
| def __init__(self, sublist): | |
| """Mox comparator which returns True if the argument | |
| to the mocked function is a list that contains sublist | |
| as a sub-list. | |
| """ | |
| self._sublist = sublist | |
| def equals(self, rhs): | |
| n = len(self._sublist) | |
| if len(rhs)<n: | |
| return False | |
| return any((self._sublist == rhs[i:i+n]) | |
| for i in xrange(len(rhs) - n + 1)) | |
| class TestRunnerUnittests(unittest.TestCase): | |
| def test_fetch_local_suite(self): | |
| # Deferred until fetch_local_suite knows about non-local builds. | |
| pass | |
| def test_get_predicate_for_test_arg(self): | |
| # Assert the type signature of get_predicate_for_test(...) | |
| # Because control.test_utils_wrapper calls this function, | |
| # it is imperative for backwards compatilbility that | |
| # the return type of the tested function does not change. | |
| tests = ['dummy_test', 'e:name_expression', 'f:expression', | |
| 'suite:suitename'] | |
| for test in tests: | |
| pred, desc = test_runner_utils.get_predicate_for_test_arg(test) | |
| self.assertTrue(isinstance(pred, types.FunctionType)) | |
| self.assertTrue(isinstance(desc, str)) | |
| def test_run_job(self): | |
| class Object(): | |
| pass | |
| autotest_path = 'htap_tsetotua' | |
| autoserv_command = os.path.join(autotest_path, 'server', 'autoserv') | |
| remote = 'etomer' | |
| results_dir = '/tmp/fakeresults' | |
| fast_mode = False | |
| job1_results_dir = '/tmp/fakeresults/results-1-gilbert' | |
| job2_results_dir = '/tmp/fakeresults/results-2-sullivan' | |
| args = 'matey' | |
| expected_args_sublist = ['--args', args] | |
| experimental_keyval = {constants.JOB_EXPERIMENTAL_KEY: False} | |
| self.mox = mox.Mox() | |
| # Create some dummy job objects. | |
| job1 = Object() | |
| job2 = Object() | |
| setattr(job1, 'control_type', 'cLiEnT') | |
| setattr(job1, 'control_file', 'c1') | |
| setattr(job1, 'id', 1) | |
| setattr(job1, 'name', 'gilbert') | |
| setattr(job1, 'keyvals', experimental_keyval) | |
| setattr(job2, 'control_type', 'Server') | |
| setattr(job2, 'control_file', 'c2') | |
| setattr(job2, 'id', 2) | |
| setattr(job2, 'name', 'sullivan') | |
| setattr(job2, 'keyvals', experimental_keyval) | |
| id_digits = 1 | |
| # Stub out subprocess.Popen and wait calls. | |
| # Make them expect correct arguments. | |
| def fake_readline(): | |
| return b'' | |
| mock_process_1 = self.mox.CreateMock(subprocess.Popen) | |
| mock_process_2 = self.mox.CreateMock(subprocess.Popen) | |
| fake_stdout = self.mox.CreateMock(file) | |
| fake_returncode = 0 | |
| mock_process_1.stdout = fake_stdout | |
| mock_process_1.returncode = fake_returncode | |
| mock_process_2.stdout = fake_stdout | |
| mock_process_2.returncode = fake_returncode | |
| self.mox.StubOutWithMock(os, 'makedirs') | |
| self.mox.StubOutWithMock(utils, 'write_keyval') | |
| self.mox.StubOutWithMock(subprocess, 'Popen') | |
| os.makedirs(job1_results_dir) | |
| utils.write_keyval(job1_results_dir, experimental_keyval) | |
| arglist_1 = [autoserv_command, '-p', '-r', job1_results_dir, | |
| '-m', remote, '--no_console_prefix', '-l', 'gilbert', | |
| '-c'] | |
| subprocess.Popen(mox.And(StartsWithList(arglist_1), | |
| ContainsSublist(expected_args_sublist)), | |
| stdout=subprocess.PIPE, | |
| stderr=subprocess.STDOUT | |
| ).AndReturn(mock_process_1) | |
| mock_process_1.stdout.readline().AndReturn(b'') | |
| mock_process_1.wait().AndReturn(0) | |
| os.makedirs(job2_results_dir) | |
| utils.write_keyval(job2_results_dir, experimental_keyval) | |
| arglist_2 = [autoserv_command, '-p', '-r', job2_results_dir, | |
| '-m', remote, '--no_console_prefix', '-l', 'sullivan', | |
| '-s'] | |
| subprocess.Popen(mox.And(StartsWithList(arglist_2), | |
| ContainsSublist(expected_args_sublist)), | |
| stdout=subprocess.PIPE, | |
| stderr=subprocess.STDOUT | |
| ).AndReturn(mock_process_2) | |
| mock_process_2.stdout.readline().AndReturn(b'') | |
| mock_process_2.wait().AndReturn(0) | |
| # Test run_job. | |
| self.mox.ReplayAll() | |
| code, job_res = test_runner_utils.run_job( | |
| job1, remote, autotest_path,results_dir, fast_mode, id_digits, | |
| 0, None, args) | |
| self.assertEqual(job_res, job1_results_dir) | |
| self.assertEqual(code, 0) | |
| code, job_res = test_runner_utils.run_job( | |
| job2, remote, autotest_path, results_dir, fast_mode, id_digits, | |
| 0, None, args) | |
| self.assertEqual(job_res, job2_results_dir) | |
| self.assertEqual(code, 0) | |
| self.mox.UnsetStubs() | |
| self.mox.VerifyAll() | |
| self.mox.ResetAll() | |
| def test_perform_local_run(self): | |
| afe = test_runner_utils.setup_local_afe() | |
| autotest_path = 'ottotest_path' | |
| suite_name = 'sweet_name' | |
| test_arg = 'suite:' + suite_name | |
| remote = 'remoat' | |
| build = 'bild' | |
| board = 'bored' | |
| fast_mode = False | |
| suite_control_files = ['c1', 'c2', 'c3', 'c4'] | |
| results_dir = '/tmp/test_that_results_fake' | |
| id_digits = 1 | |
| ssh_verbosity = 2 | |
| ssh_options = '-F /dev/null -i /dev/null' | |
| args = 'matey' | |
| ignore_deps = False | |
| # Fake suite objects that will be returned by fetch_local_suite | |
| class fake_suite(object): | |
| def __init__(self, suite_control_files, hosts): | |
| self._suite_control_files = suite_control_files | |
| self._hosts = hosts | |
| def schedule(self, *args, **kwargs): | |
| for control_file in self._suite_control_files: | |
| afe.create_job(control_file, hosts=self._hosts) | |
| # Mock out scheduling of suite and running of jobs. | |
| self.mox = mox.Mox() | |
| self.mox.StubOutWithMock(test_runner_utils, 'fetch_local_suite') | |
| test_runner_utils.fetch_local_suite(autotest_path, mox.IgnoreArg(), | |
| afe, test_arg=test_arg, remote=remote, build=build, | |
| board=board, results_directory=results_dir, | |
| no_experimental=False, | |
| ignore_deps=ignore_deps | |
| ).AndReturn(fake_suite(suite_control_files, [remote])) | |
| self.mox.StubOutWithMock(test_runner_utils, 'run_job') | |
| self.mox.StubOutWithMock(test_runner_utils, 'run_provisioning_job') | |
| self.mox.StubOutWithMock(test_runner_utils, '_auto_detect_labels') | |
| test_runner_utils._auto_detect_labels(afe, remote) | |
| # Test perform_local_run. Enforce that run_provisioning_job, | |
| # run_job and _auto_detect_labels are called correctly. | |
| test_runner_utils.run_provisioning_job( | |
| 'cros-version:' + build, remote, autotest_path, | |
| results_dir, fast_mode, | |
| ssh_verbosity, ssh_options, | |
| False, False) | |
| for control_file in suite_control_files: | |
| test_runner_utils.run_job( | |
| mox.ContainsAttributeValue('control_file', control_file), | |
| remote, autotest_path, results_dir, fast_mode,id_digits, | |
| ssh_verbosity, ssh_options,args, False, | |
| False, {}).AndReturn((0, '/fake/dir')) | |
| self.mox.ReplayAll() | |
| test_runner_utils.perform_local_run( | |
| afe, autotest_path, ['suite:'+suite_name], remote, fast_mode, | |
| build=build, board=board, ignore_deps=False, | |
| ssh_verbosity=ssh_verbosity, ssh_options=ssh_options, | |
| args=args, results_directory=results_dir) | |
| self.mox.UnsetStubs() | |
| self.mox.VerifyAll() | |
| if __name__ == '__main__': | |
| unittest.main() |