Home | History | Annotate | Download | only in server
      1 # Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
      2 # Use of this source code is governed by a BSD-style license that can be
      3 # found in the LICENSE file.
      4 
      5 """Utility classes used by server_job.distribute_across_machines().
      6 
      7 test_item: extends the basic test tuple to add include/exclude attributes and
      8     pre/post actions.
      9 """
     10 
     11 
     12 import logging, os, Queue
     13 from autotest_lib.client.common_lib import error, utils
     14 from autotest_lib.server import autotest, hosts, host_attributes
     15 
     16 
     17 class test_item(object):
     18     """Adds machine verification logic to the basic test tuple.
     19 
     20     Tests can either be tuples of the existing form ('testName', {args}) or the
     21     extended form ('testname', {args}, {'include': [], 'exclude': [],
     22     'attributes': []}) where include and exclude are lists of host attribute
     23     labels and attributes is a list of strings. A machine must have all the
     24     labels in include and must not have any of the labels in exclude to be valid
     25     for the test. Attributes strings can include reboot_before, reboot_after,
     26     and server_job.
     27     """
     28 
     29     def __init__(self, test_name, test_args, test_attribs=None):
     30         """Creates an instance of test_item.
     31 
     32         Args:
     33             test_name: string, name of test to execute.
     34             test_args: dictionary, arguments to pass into test.
     35             test_attribs: Dictionary of test attributes. Valid keys are:
     36               include - labels a machine must have to run a test.
     37               exclude - labels preventing a machine from running a test.
     38               attributes - reboot before/after test, run test as server job.
     39         """
     40         self.test_name = test_name
     41         self.test_args = test_args
     42         self.tagged_test_name = test_name
     43         if test_args.get('tag'):
     44             self.tagged_test_name = test_name + '.' + test_args.get('tag')
     45 
     46         if test_attribs is None:
     47             test_attribs = {}
     48         self.inc_set = set(test_attribs.get('include', []))
     49         self.exc_set = set(test_attribs.get('exclude', []))
     50         self.attributes = test_attribs.get('attributes', [])
     51 
     52     def __str__(self):
     53         """Return an info string of this test."""
     54         params = ['%s=%s' % (k, v) for k, v in self.test_args.items()]
     55         msg = '%s(%s)' % (self.test_name, params)
     56         if self.inc_set:
     57             msg += ' include=%s' % [s for s in self.inc_set]
     58         if self.exc_set:
     59             msg += ' exclude=%s' % [s for s in self.exc_set]
     60         if self.attributes:
     61             msg += ' attributes=%s' % self.attributes
     62         return msg
     63 
     64     def validate(self, machine_attributes):
     65         """Check if this test can run on machine with machine_attributes.
     66 
     67         If the test has include attributes, a candidate machine must have all
     68         the attributes to be valid.
     69 
     70         If the test has exclude attributes, a candidate machine cannot have any
     71         of the attributes to be valid.
     72 
     73         Args:
     74             machine_attributes: set, True attributes of candidate machine.
     75 
     76         Returns:
     77             True/False if the machine is valid for this test.
     78         """
     79         if self.inc_set is not None:
     80             if not self.inc_set <= machine_attributes:
     81                 return False
     82         if self.exc_set is not None:
     83             if self.exc_set & machine_attributes:
     84                 return False
     85         return True
     86 
     87     def run_test(self, client_at, work_dir='.', server_job=None):
     88         """Runs the test on the client using autotest.
     89 
     90         Args:
     91             client_at: Autotest instance for this host.
     92             work_dir: Directory to use for results and log files.
     93             server_job: Server_Job instance to use to runs server tests.
     94         """
     95         if 'reboot_before' in self.attributes:
     96             client_at.host.reboot()
     97 
     98         try:
     99             if 'server_job' in self.attributes:
    100                 if 'host' in self.test_args:
    101                     self.test_args['host'] = client_at.host
    102                 if server_job is not None:
    103                     logging.info('Running Server_Job=%s', self.test_name)
    104                     server_job.run_test(self.test_name, **self.test_args)
    105                 else:
    106                     logging.error('No Server_Job instance provided for test '
    107                                   '%s.', self.test_name)
    108             else:
    109                 client_at.run_test(self.test_name, results_dir=work_dir,
    110                                    **self.test_args)
    111         finally:
    112             if 'reboot_after' in self.attributes:
    113                 client_at.host.reboot()
    114