Home | History | Annotate | Download | only in site_utils
      1 #!/usr/bin/python
      2 # Copyright 2015 The Chromium OS Authors. All rights reserved.
      3 # Use of this source code is governed by a BSD-style license that can be
      4 # found in the LICENSE file.
      5 # pylint: disable-msg=C0111
      6 
      7 import os, unittest
      8 import mox
      9 import common
     10 import subprocess
     11 import types
     12 from autotest_lib.server import utils
     13 from autotest_lib.server.cros.dynamic_suite import constants
     14 from autotest_lib.site_utils import test_runner_utils
     15 
     16 
     17 class StartsWithList(mox.Comparator):
     18     def __init__(self, start_of_list):
     19         """Mox comparator which returns True if the argument
     20         to the mocked function is a list that begins with the elements
     21         in start_of_list.
     22         """
     23         self._lhs = start_of_list
     24 
     25     def equals(self, rhs):
     26         if len(rhs)<len(self._lhs):
     27             return False
     28         for (x, y) in zip(self._lhs, rhs):
     29             if x != y:
     30                 return False
     31         return True
     32 
     33 
     34 class ContainsSublist(mox.Comparator):
     35     def __init__(self, sublist):
     36         """Mox comparator which returns True if the argument
     37         to the mocked function is a list that contains sublist
     38         as a sub-list.
     39         """
     40         self._sublist = sublist
     41 
     42     def equals(self, rhs):
     43         n = len(self._sublist)
     44         if len(rhs)<n:
     45             return False
     46         return any((self._sublist == rhs[i:i+n])
     47                    for i in xrange(len(rhs) - n + 1))
     48 
     49 
     50 class TestRunnerUnittests(unittest.TestCase):
     51 
     52     def test_fetch_local_suite(self):
     53         # Deferred until fetch_local_suite knows about non-local builds.
     54         pass
     55 
     56     def test_get_predicate_for_test_arg(self):
     57         # Assert the type signature of get_predicate_for_test(...)
     58         # Because control.test_utils_wrapper calls this function,
     59         # it is imperative for backwards compatilbility that
     60         # the return type of the tested function does not change.
     61         tests = ['dummy_test', 'e:name_expression', 'f:expression',
     62                  'suite:suitename']
     63         for test in tests:
     64             pred, desc = test_runner_utils.get_predicate_for_test_arg(test)
     65             self.assertTrue(isinstance(pred, types.FunctionType))
     66             self.assertTrue(isinstance(desc, str))
     67 
     68     def test_run_job(self):
     69         class Object():
     70             pass
     71 
     72         autotest_path = 'htap_tsetotua'
     73         autoserv_command = os.path.join(autotest_path, 'server', 'autoserv')
     74         remote = 'etomer'
     75         results_dir = '/tmp/fakeresults'
     76         fast_mode = False
     77         job1_results_dir = '/tmp/fakeresults/results-1-gilbert'
     78         job2_results_dir = '/tmp/fakeresults/results-2-sullivan'
     79         args = 'matey'
     80         expected_args_sublist = ['--args', args]
     81         experimental_keyval = {constants.JOB_EXPERIMENTAL_KEY: False}
     82         self.mox = mox.Mox()
     83 
     84         # Create some dummy job objects.
     85         job1 = Object()
     86         job2 = Object()
     87         setattr(job1, 'control_type', 'cLiEnT')
     88         setattr(job1, 'control_file', 'c1')
     89         setattr(job1, 'id', 1)
     90         setattr(job1, 'name', 'gilbert')
     91         setattr(job1, 'keyvals', experimental_keyval)
     92 
     93         setattr(job2, 'control_type', 'Server')
     94         setattr(job2, 'control_file', 'c2')
     95         setattr(job2, 'id', 2)
     96         setattr(job2, 'name', 'sullivan')
     97         setattr(job2, 'keyvals', experimental_keyval)
     98 
     99         id_digits = 1
    100 
    101         # Stub out subprocess.Popen and wait calls.
    102         # Make them expect correct arguments.
    103         def fake_readline():
    104             return b''
    105         mock_process_1 = self.mox.CreateMock(subprocess.Popen)
    106         mock_process_2 = self.mox.CreateMock(subprocess.Popen)
    107         fake_stdout = self.mox.CreateMock(file)
    108         fake_returncode = 0
    109         mock_process_1.stdout = fake_stdout
    110         mock_process_1.returncode = fake_returncode
    111         mock_process_2.stdout = fake_stdout
    112         mock_process_2.returncode = fake_returncode
    113 
    114         self.mox.StubOutWithMock(os, 'makedirs')
    115         self.mox.StubOutWithMock(utils, 'write_keyval')
    116         self.mox.StubOutWithMock(subprocess, 'Popen')
    117 
    118         os.makedirs(job1_results_dir)
    119         utils.write_keyval(job1_results_dir, experimental_keyval)
    120         arglist_1 = [autoserv_command, '-p', '-r', job1_results_dir,
    121                      '-m', remote, '--no_console_prefix', '-l', 'gilbert',
    122                      '-c']
    123         subprocess.Popen(mox.And(StartsWithList(arglist_1),
    124                                  ContainsSublist(expected_args_sublist)),
    125                          stdout=subprocess.PIPE,
    126                          stderr=subprocess.STDOUT
    127                         ).AndReturn(mock_process_1)
    128         mock_process_1.stdout.readline().AndReturn(b'')
    129         mock_process_1.wait().AndReturn(0)
    130 
    131         os.makedirs(job2_results_dir)
    132         utils.write_keyval(job2_results_dir, experimental_keyval)
    133         arglist_2 = [autoserv_command, '-p', '-r', job2_results_dir,
    134                      '-m', remote,  '--no_console_prefix', '-l', 'sullivan',
    135                      '-s']
    136         subprocess.Popen(mox.And(StartsWithList(arglist_2),
    137                                  ContainsSublist(expected_args_sublist)),
    138                          stdout=subprocess.PIPE,
    139                          stderr=subprocess.STDOUT
    140                         ).AndReturn(mock_process_2)
    141         mock_process_2.stdout.readline().AndReturn(b'')
    142         mock_process_2.wait().AndReturn(0)
    143 
    144         # Test run_job.
    145         self.mox.ReplayAll()
    146         code, job_res = test_runner_utils.run_job(
    147                 job1, remote, autotest_path,results_dir, fast_mode, id_digits,
    148                 0, None, args)
    149         self.assertEqual(job_res, job1_results_dir)
    150         self.assertEqual(code, 0)
    151         code, job_res = test_runner_utils.run_job(
    152                 job2, remote, autotest_path, results_dir, fast_mode, id_digits,
    153                 0, None, args)
    154 
    155         self.assertEqual(job_res, job2_results_dir)
    156         self.assertEqual(code, 0)
    157         self.mox.UnsetStubs()
    158         self.mox.VerifyAll()
    159         self.mox.ResetAll()
    160 
    161     def test_perform_local_run(self):
    162         afe = test_runner_utils.setup_local_afe()
    163         autotest_path = 'ottotest_path'
    164         suite_name = 'sweet_name'
    165         test_arg = 'suite:' + suite_name
    166         remote = 'remoat'
    167         build = 'bild'
    168         board = 'bored'
    169         fast_mode = False
    170         suite_control_files = ['c1', 'c2', 'c3', 'c4']
    171         results_dir = '/tmp/test_that_results_fake'
    172         id_digits = 1
    173         ssh_verbosity = 2
    174         ssh_options = '-F /dev/null -i /dev/null'
    175         args = 'matey'
    176         ignore_deps = False
    177 
    178         # Fake suite objects that will be returned by fetch_local_suite
    179         class fake_suite(object):
    180             def __init__(self, suite_control_files, hosts):
    181                 self._suite_control_files = suite_control_files
    182                 self._hosts = hosts
    183 
    184             def schedule(self, *args, **kwargs):
    185                 for control_file in self._suite_control_files:
    186                     afe.create_job(control_file, hosts=self._hosts)
    187 
    188         # Mock out scheduling of suite and running of jobs.
    189         self.mox = mox.Mox()
    190 
    191         self.mox.StubOutWithMock(test_runner_utils, 'fetch_local_suite')
    192         test_runner_utils.fetch_local_suite(autotest_path, mox.IgnoreArg(),
    193                 afe, test_arg=test_arg, remote=remote, build=build,
    194                 board=board, results_directory=results_dir,
    195                 no_experimental=False,
    196                 ignore_deps=ignore_deps
    197                 ).AndReturn(fake_suite(suite_control_files, [remote]))
    198         self.mox.StubOutWithMock(test_runner_utils, 'run_job')
    199         self.mox.StubOutWithMock(test_runner_utils, 'run_provisioning_job')
    200         self.mox.StubOutWithMock(test_runner_utils, '_auto_detect_labels')
    201 
    202         test_runner_utils._auto_detect_labels(afe, remote)
    203         # Test perform_local_run. Enforce that run_provisioning_job,
    204         # run_job and _auto_detect_labels are called correctly.
    205         test_runner_utils.run_provisioning_job(
    206                 'cros-version:' + build, remote, autotest_path,
    207                  results_dir, fast_mode,
    208                  ssh_verbosity, ssh_options,
    209                  False, False)
    210 
    211         for control_file in suite_control_files:
    212             test_runner_utils.run_job(
    213                     mox.ContainsAttributeValue('control_file', control_file),
    214                     remote, autotest_path, results_dir, fast_mode,id_digits,
    215                     ssh_verbosity, ssh_options,args, False,
    216                     False, {}).AndReturn((0, '/fake/dir'))
    217         self.mox.ReplayAll()
    218         test_runner_utils.perform_local_run(
    219                 afe, autotest_path, ['suite:'+suite_name], remote, fast_mode,
    220                 build=build, board=board, ignore_deps=False,
    221                 ssh_verbosity=ssh_verbosity, ssh_options=ssh_options,
    222                 args=args, results_directory=results_dir)
    223         self.mox.UnsetStubs()
    224         self.mox.VerifyAll()
    225 
    226 
    227 if __name__ == '__main__':
    228     unittest.main()
    229