Go to the documentation of this file.00001 
00002 
00003 
00004 
00005 
00006 
00007 
00008 
00009 
00010 
00011 
00012 
00013 
00014 
00015 
00016 
00017 
00018 
00019 
00020 
00021 
00022 
00023 
00024 
00025 
00026 
00027 
00028 
00029 
00030 
00031 
00032 
00033 
00034 
00035 
00036 
00037 PKG = 'life_test'
00038 import roslib
00039 roslib.load_manifest(PKG)
00040 
00041 import rospy
00042 
00043 from writing_core import *
00044 
00045 
00046 class LifeTest(object):
00047     """
00048     Holds parameters, info for each life test
00049     """
00050     def __init__(self, short = '', testid = '', name = '', desc = '', serial = '',
00051                  duration = 0, launch_script = '', test_type = '', power = False, params = None):
00052         """
00053         Use **kwargs in constructor. Preferred option is to initialize from XML
00054         """
00055         self._short_serial = serial
00056         self._id = testid
00057         self._name = name
00058         self._short = short
00059         self._duration = duration
00060         self._desc = desc
00061         self._launch_script = launch_script
00062         self._test_type = test_type
00063         self._power = power
00064 
00065         self._params = params if params else []
00066 
00067         self._debug_ok = False
00068         
00069         self._has_init = self._short_serial != '' and self._id != '' and self._name != '' \
00070             and self._launch_script != ''
00071 
00072 
00073     def init_xml(self, xml):
00074         """
00075         Initialize LifeTest from XML value. 
00076         
00077         Required tags:
00078         serial - Short value only
00079         name - Full name of test
00080         id - Test ID
00081         desc - Description
00082         script - Path to launch script
00083         type - Ex: 'Burn In'
00084         power - Needs power or not (bool)
00085         
00086         Optional:
00087         debug - "true" if can run outside debug mode
00088         duration - Default: 0
00089 
00090         TestParam's are initialized using nested XML nodes
00091         @raise Exception : If parameters are duplicated, or required attributes don't exist
00092         @return bool : True if init OK
00093         """
00094         self._short_serial = xml.attributes['serial'].value 
00095         self._name = xml.attributes['name'].value
00096         self._id = xml.attributes['id'].value
00097         self._desc = xml.attributes['desc'].value
00098         self._launch_script = xml.attributes['script'].value
00099         self._test_type = xml.attributes['type'].value
00100         self._short = xml.attributes['short'].value
00101         self._power = xml.attributes['power'].value != 'false'
00102 
00103         self._debug_ok = xml.attributes.has_key('debug') and \
00104             xml.attributes['debug'].value.lower() == "true"
00105         
00106         if xml.attributes.has_key('duration'):
00107             self._duration = int(xml.attributes['duration'].value)
00108 
00109         params_xml = xml.getElementsByTagName('param')
00110         for param_xml in params_xml:
00111             my_param = TestParam()
00112             my_param.init_xml(param_xml)
00113 
00114             names = [ p.name for p in self._params ]
00115             if my_param.name in names:
00116                 raise Exception("Param %s already exists in param list! XML: %s" % (my_param.name, xml.toprettyxml()))
00117 
00118             self._params.append(my_param)
00119 
00120         self._has_init = True
00121         return True
00122     
00123     @property
00124     def debug_ok(self): return self._debug_ok
00125 
00126     @property
00127     def need_power(self): return self._power
00128 
00129     @property
00130     def short(self):
00131         return self._short
00132 
00133     @property
00134     def desc(self):
00135         """Get description of test"""
00136         return self._desc
00137 
00138     @property
00139     def params(self): 
00140         """Get the parameters list. Read-only"""
00141         return self._params
00142 
00143     @property
00144     def duration(self): return self._duration
00145 
00146     @property
00147     def name(self): return self._name
00148 
00149     @property
00150     def id(self): return self._id
00151 
00152     @property
00153     def type(self): return self._test_type
00154 
00155     @property
00156     def needs_power(self):
00157         return self.need_power
00158     
00159     @property
00160     def launch_file(self):
00161         return self._launch_script
00162 
00163     def set_params(self, namespace):
00164         """
00165         Sets parameters in given namespace
00166         """
00167         for param in self._params:
00168             param.set_namespace(namespace)
00169 
00170 
00171     def get_title(self, serial):
00172         """
00173         Return a human readable title of the test/item. Used as tab name
00174         """
00175         if len(serial) == 12: 
00176             return "%s %s" % (self._short, 
00177                                  serial[len(serial) - 3: 
00178                                         len(serial)])
00179         
00180         return self._short
00181 
00182 
00183     def validate(self):
00184         """
00185         Called during unit testing only. Checks all files exist, are valid
00186         @return bool : True if OK
00187         """
00188         if not self._has_init:
00189             return False
00190 
00191         import os, sys
00192 
00193         full_path = os.path.join(roslib.packages.get_pkg_dir(PKG), self._launch_script)
00194 
00195         if not os.path.exists(full_path):
00196             print >> sys.stderr, "Test %s, path %s doesn't exist" % (self._name, full_path)
00197             return False
00198         if not full_path.endswith('.launch'):
00199             print >> sys.stderr, "Test %s, path %s is not a launch file" % (self._name, full_path)
00200             return False
00201 
00202         return True
00203 
00204     def make_param_table(self):
00205         """
00206         Writes parameters to HTML table form for logging
00207         @return str : Table as a string
00208         """
00209         if len(self._params) == 0:
00210             return '<p>No test parameters defined.</p>\n'
00211 
00212         html = '<table border="1" cellpadding="2" cellspacing="0">\n'
00213         html += write_table_row(['Name', 'Value', 'Key', 'Description'], True)
00214         for param in self._params:
00215             html += write_table_row([param._name, param._value, param._param_name, param._desc])
00216         html += '</table>\n'
00217 
00218         return html
00219             
00220         
00221 
00222 
00223 
00224 
00225 class TestParam(object):
00226     def __init__(self):
00227         self._value = ''
00228         self._desc = ''
00229 
00230         self._cumulative = ''
00231         self._param_name = ''
00232         self._name = ''
00233         self._namespace = ''
00234 
00235     def init_xml(self, param_xml):
00236         """
00237         Initialize from XML
00238 
00239         Required elements:
00240         name - Name of param
00241         param_name - ROS name of param
00242         desc - Description
00243         value - Value of param
00244         rate = "true" if parameters is cumulative, or a rate
00245         
00246         @raise Exception : If required attribs aren't present
00247         @return bool : True if OK
00248         """
00249         self._name = param_xml.attributes['name'].value
00250         self._param_name = param_xml.attributes['param_name'].value
00251         self._desc = param_xml.attributes['desc'].value
00252         self._value = param_xml.attributes['val'].value
00253         self._cumulative = param_xml.attributes['rate'].value == 'true'
00254 
00255         return True
00256  
00257     def set_namespace(self, ns):
00258         """
00259         Set parameter's value in appropriate namespace
00260         """
00261         self._namespace = ns
00262         rospy.set_param('/' + self._namespace + '/' + self._param_name, self._value)
00263 
00264     @property
00265     def value(self):
00266         try:
00267             val = float(self._value)
00268             return val
00269         except:
00270             return str(self._value)
00271 
00272     @property
00273     def name(self): return self._name
00274 
00275     @property
00276     def rate(self):
00277         return self._cumulative
00278