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 = 'qualification'
00038 import roslib; roslib.load_manifest(PKG)
00039
00040 import rospy
00041
00042 import os
00043 import sys
00044 import socket
00045 import wx
00046
00047 from wx import xrc
00048 from wx import html
00049
00050 from xml.dom import minidom
00051
00052 from qualification.test import *
00053 from qualification.qual_frame import *
00054
00055 from qualification.test_loader import load_configs_from_map, load_tests_from_map, load_wg_station_map
00056
00057 TESTS_DIR = os.path.join(roslib.packages.get_pkg_dir(PKG), 'tests')
00058 CONFIG_DIR = os.path.join(roslib.packages.get_pkg_dir(PKG), 'config')
00059
00060 class ConfigObject(QualTestObject):
00061 def __init__(self, name, serial):
00062 QualTestObject.__init__(self, name, serial)
00063 self._config = True
00064
00065 class ComponentQualOptions(QualOptions):
00066 def __init__(self):
00067 QualOptions.__init__(self)
00068
00069
00070
00071 class SerialPanel(wx.Panel):
00072
00073
00074
00075 def __init__(self, parent, resource, qualification_frame):
00076 wx.Panel.__init__(self, parent)
00077
00078 self._manager = qualification_frame
00079
00080 self._res = resource
00081
00082 self._tests = {}
00083 self._debugs = []
00084 self._configs = {}
00085 loaded_ok = self.load_test_config_files()
00086
00087 self._panel = resource.LoadPanel(self, 'serial_panel')
00088 self._sizer = wx.BoxSizer(wx.HORIZONTAL)
00089
00090 self._sizer.Add(self._panel, 1, wx.EXPAND|wx.ALIGN_CENTER_VERTICAL)
00091 self.SetSizer(self._sizer)
00092 self.Layout()
00093 self.Fit()
00094
00095
00096 self._test_button = xrc.XRCCTRL(self._panel, 'test_button')
00097 self._serial_text = xrc.XRCCTRL(self._panel, 'serial_text')
00098
00099 self._test_button.Bind(wx.EVT_BUTTON, self.on_test)
00100
00101
00102 self._serial_text_conf = xrc.XRCCTRL(self._panel, 'serial_text_conf')
00103
00104 self._config_button = xrc.XRCCTRL(self._panel, 'config_button')
00105 self._config_button.Bind(wx.EVT_BUTTON, self.on_config)
00106
00107
00108 self._notebook = xrc.XRCCTRL(self._panel, 'test_tab_control')
00109 self._notebook.ChangeSelection(0)
00110
00111 self._panel.Bind(wx.EVT_CHAR, self.on_char)
00112 self._serial_text.SetFocus()
00113
00114 if not loaded_ok:
00115 wx.MessageBox("Warning: Unable to load tests configuration files. May be corrupt. Revert any changes you have made to these files and retry", "Invalid Configuration Files", wx.OK|wx.ICON_ERROR, self)
00116
00117
00118 def load_test_config_files(self):
00119 """
00120 Called at startup or by menu option. Loads configuration files that define tests.
00121 """
00122 tests = {}
00123 debugs = []
00124 try:
00125 tests_ok = load_tests_from_map(tests, debugs)
00126 if tests_ok:
00127 self._debugs = debugs
00128 self._tests = tests
00129 except Exception, e:
00130 tests_ok = False
00131
00132 configs = {}
00133 try:
00134 configs_ok = load_configs_from_map(configs)
00135 if configs_ok:
00136 self._configs = configs
00137 except Exception, e:
00138 configs_ok = False
00139
00140 return tests_ok and configs_ok
00141
00142 def _is_debug_test(self, serial):
00143 return serial[0:7] in self._debugs
00144
00145
00146
00147
00148
00149 def _check_serial_input(self, serial, check_pass = False):
00150 if self._manager.options.debug:
00151 return True
00152
00153 if self._is_debug_test(serial):
00154 return True
00155
00156 iv = self._manager.get_inventory_object()
00157 if not iv or not iv.login():
00158 wx.MessageBox("Unable to check serial number. Unable to login in Inventory system", "Error - Unable to check serial number", wx.OK|wx.ICON_ERROR, self)
00159 return False
00160
00161 if check_pass and not iv.get_test_status(serial):
00162 wx.MessageBox("Component has not passed qualification. Please qualify the component.", "Error - Unqualified Component", wx.OK|wx.ICON_ERROR, self)
00163 return False
00164
00165 return iv.check_serial_valid(serial)
00166
00167 def on_config(self, event):
00168
00169 serial = str(self._serial_text_conf.GetValue())
00170
00171 if not self._check_serial_input(serial, True):
00172 wx.MessageBox('Invalid serial number, unable to configure. Check serial number and retry.','Error - Invalid serial number', wx.OK|wx.ICON_ERROR, self)
00173 return
00174
00175 if not self.has_conf_script(serial):
00176 wx.MessageBox('No configuration procedure defined for that serial number.','Error - Invalid serial number', wx.OK|wx.ICON_ERROR, self)
00177 return
00178
00179 config_test = self.select_conf_to_load(serial)
00180 if config_test is None:
00181 return
00182
00183 if not config_test.validate():
00184 wx.MessageBox('Unable to load configuration data and parameters. Check file and try again.','Failed to load test', wx.OK|wx.ICON_ERROR, self)
00185 return
00186
00187 item = ConfigObject(config_test.get_name(), serial)
00188
00189 self._manager.begin_test(config_test, item)
00190
00191 def has_conf_script(self, serial):
00192 return self._configs.has_key(serial[0:7])
00193
00194 def has_test(self, serial):
00195 return self._tests.has_key(serial[0:7])
00196
00197 def _check_assembly(self, serial):
00198 if self._manager.options.debug:
00199 return True
00200
00201 if self._is_debug_test(serial):
00202 return True
00203
00204 iv = self._manager.get_inventory_object()
00205
00206 return iv.check_assembled(serial, recursive = True)
00207
00208 def on_test(self, event):
00209 serial = self._serial_text.GetValue()
00210
00211 if not self._check_serial_input(serial):
00212 wx.MessageBox('Invalid serial number, unable to test component. Check serial number and retry.','Error - Invalid serial number', wx.OK|wx.ICON_ERROR, self)
00213 return
00214
00215 if not self.has_test(serial):
00216 wx.MessageBox('No test defined for that serial number.','Error - Invalid serial number', wx.OK|wx.ICON_ERROR, self)
00217 return
00218
00219 short_serial = serial[0:7]
00220
00221 my_test = self.select_test_to_load(short_serial)
00222
00223 if my_test is None:
00224 return
00225
00226 if not my_test.validate():
00227 wx.MessageBox('Unable to load test data and parameters. Check file and try again.','Failed to load test', wx.OK|wx.ICON_ERROR, self)
00228 return
00229
00230 if my_test.check_assembly and not self._check_assembly(serial):
00231 wx.MessageBox('Component is not properly assembled in Invent. Use the "Assemble" page in Invent to verify component assembly.',
00232 'Component Not Assembled', wx.OK|wx.ICON_ERROR, self)
00233 return
00234
00235
00236
00237 item = QualTestObject(my_test.get_name(), serial)
00238
00239 self._manager.begin_test(my_test, item)
00240
00241
00242 def select_string_from_list(self, msg, lst):
00243 if len(lst) == 1:
00244 return lst[0]
00245
00246
00247 dialog = self._res.LoadDialog(self, 'select_test_dialog')
00248 select_text = xrc.XRCCTRL(dialog, 'select_text')
00249 select_text.SetLabel(msg)
00250 test_box = xrc.XRCCTRL(dialog, 'test_list_box')
00251 test_box.InsertItems(lst, 0)
00252 test_box.SetSelection(0)
00253
00254 select_text.Wrap(270)
00255
00256 dialog.Layout()
00257
00258
00259 if (dialog.ShowModal() == wx.ID_OK):
00260 desc = test_box.GetStringSelection()
00261 dialog.Destroy()
00262 return desc
00263 else:
00264 dialog.Destroy()
00265 return None
00266
00267 def select_conf_to_load(self, serial):
00268 short_serial = serial[0:7]
00269
00270
00271 configs_by_descrip = {}
00272 for conf in self._configs[short_serial]:
00273 configs_by_descrip[conf.get_name()] = conf
00274
00275 msg = 'Select configuration type'
00276
00277 descrips = configs_by_descrip.keys()
00278 descrips.sort()
00279
00280 choice = self.select_string_from_list(msg, descrips)
00281 if choice is None:
00282 return None
00283 return configs_by_descrip[choice]
00284
00285
00286 def select_test_to_load(self, short_serial):
00287
00288 tests_by_descrip = {}
00289 for test in self._tests[short_serial]:
00290 tests_by_descrip[test.get_name()] = test
00291
00292 descrips = tests_by_descrip.keys()
00293 descrips.sort()
00294
00295 msg = 'Select component or component type to qualify.'
00296
00297 choice = self.select_string_from_list(msg, descrips)
00298 if choice is None:
00299 return None
00300 return tests_by_descrip[choice]
00301
00302 def on_char(self, event):
00303
00304 if (event.GetKeyCode() == 347):
00305
00306 self._serial_text.Clear()
00307 self._serial_text_conf.Clear()
00308
00309 class ComponentQualFrame(QualificationFrame):
00310 def __init__(self, parent, options):
00311 self._serial_panel = None
00312 QualificationFrame.__init__(self, parent, options)
00313
00314 self.load_wg_test_map()
00315 self.create_menubar()
00316
00317 def get_loader_panel(self):
00318 if not self._serial_panel:
00319 self._serial_panel = SerialPanel(self._top_panel, self._res, self)
00320 return self._serial_panel
00321
00322
00323 def create_menubar(self):
00324 menubar = wx.MenuBar()
00325 self._file_menu = wx.Menu()
00326 self._file_menu.Append(1001, "Invent Login\tCTRL+l")
00327 self._file_menu.Append(1002, "R&eload Test/Config Lists")
00328 self._file_menu.Append(1003, "Reload W&G Station Map")
00329 self._file_menu.Append(wx.ID_EXIT, "E&xit")
00330 menubar.Append(self._file_menu, "&File")
00331
00332 self._options_menu = wx.Menu()
00333 self._options_menu.AppendCheckItem(2001, "Always Show Results")
00334 menubar.Append(self._options_menu, "&Options")
00335
00336 self._powerboard_menu = wx.Menu()
00337 self._powerboard_menu.Append(3101, "Power Board\tCTRL+b")
00338 self._powerboard_menu.AppendCheckItem(3150, "Breaker 0\tCTRL+0")
00339 self._powerboard_menu.AppendCheckItem(3151, "Breaker 1\tCTRL+1")
00340 self._powerboard_menu.AppendCheckItem(3152, "Breaker 2\tCTRL+2")
00341 self._powerboard_menu.Check(3150, rospy.get_param('/qualification/powerboard/0'))
00342 self._powerboard_menu.Check(3151, rospy.get_param('/qualification/powerboard/1'))
00343 self._powerboard_menu.Check(3152, rospy.get_param('/qualification/powerboard/2'))
00344
00345 menubar.Append(self._powerboard_menu, "&Powerboard")
00346
00347 self._host_menu = wx.Menu()
00348 self._host_menu.Append(4001, "Select Test Host\tCTRL+h")
00349 menubar.Append(self._host_menu, "Test &Host")
00350
00351 self._debug_menu = None
00352 if self.options.debug:
00353 self._debug_menu = wx.Menu()
00354 self._debug_menu.Append(5005, "Abort Subtest")
00355 self._debug_menu.Append(5001, "Continuous Testing")
00356 menubar.Append(self._debug_menu, "Debug Mode")
00357
00358 self.SetMenuBar(menubar)
00359 self.Bind(wx.EVT_MENU, self.on_menu)
00360
00361 def get_powerboard(self):
00362 while not rospy.is_shutdown():
00363
00364 serial = wx.GetTextFromUser('Enter last four digits of power board serial number', 'Select Power Board', rospy.get_param('/qualification/powerboard/serial', ''))
00365 if len(serial) == 0:
00366 return
00367 if len(serial) == 4 and unicode(serial).isnumeric():
00368 rospy.set_param('/qualification/powerboard/serial', serial)
00369 return
00370 are_you_sure = wx.MessageDialog(self, 'Invalid powerboard ID. Retry?', 'Invalid serial',
00371 wx.OK|wx.CANCEL)
00372 if are_you_sure.ShowModal() != wx.ID_OK:
00373 return
00374
00375 def on_menu(self, event):
00376 if (event.GetEventObject() == self._file_menu):
00377 if (event.GetId() == wx.ID_EXIT):
00378 self.Close()
00379 return
00380 if (event.GetId() == 1001):
00381 self.login_to_invent()
00382 return
00383 if (event.GetId() == 1002):
00384 if not self._serial_panel.load_test_config_files():
00385 wx.MessageBox('Configuration files for loading tests are invalid. Check the files "tests/tests.xml" and "config/configs.xml" and retry.',
00386 'Invalid Configuration Files', wx.OK|wx.ICON_ERROR, self)
00387 else:
00388 wx.MessageBox('Reloaded configuration files successfully.',
00389 'Reloaded Configuration Files', wx.OK, self)
00390 return
00391 if (event.GetId() == 1003):
00392 if not self.load_wg_test_map():
00393 wx.MessageBox('Configuration file for loading WG station map is invalid. Check the file wg_map.xml" and retry.',
00394 'Invalid Configuration File', wx.OK|wx.ICON_ERROR, self)
00395 else:
00396 wx.MessageBox('Reloaded WG station map configuration file successfully.',
00397 'Reloaded Configuration File', wx.OK, self)
00398 return
00399
00400 if (event.GetEventObject() == self._options_menu):
00401 if (event.GetId() == 2001):
00402 self.options.always_show_results = self._options_menu.IsChecked(2001)
00403
00404 if (event.GetEventObject() == self._powerboard_menu):
00405 if (event.GetId() == 3101):
00406 self.get_powerboard()
00407
00408 if (event.GetId() == 3150):
00409 rospy.set_param('/qualification/powerboard/0', self._powerboard_menu.IsChecked(3150))
00410 if (event.GetId() == 3151):
00411 rospy.set_param('/qualification/powerboard/1', self._powerboard_menu.IsChecked(3151))
00412 if (event.GetId() == 3152):
00413 rospy.set_param('/qualification/powerboard/2', self._powerboard_menu.IsChecked(3152))
00414
00415 if (event.GetEventObject() == self._host_menu):
00416 if (event.GetId() == 4001):
00417 self.set_test_host()
00418
00419 if (event.GetEventObject() == self._debug_menu):
00420 if (event.GetId() == 5005):
00421 self.abort_active_test(True)
00422 if (event.GetId() == 5001):
00423 self.start_continuous_testing()
00424
00425
00426
00427 def abort_active_test(self, can_veto):
00428 if can_veto:
00429 are_you_sure = wx.MessageDialog(self, "Are you sure you want to abort the current operation?",
00430 "Confirm Abort", wx.OK|wx.CANCEL)
00431 if are_you_sure.ShowModal() != wx.ID_OK:
00432 return
00433
00434 if self._subtest_launch is not None:
00435 self.log('Aborting subtest')
00436 self.subtest_finished(subtest_timeout(0))
00437 return
00438
00439 if self._prestartup_launch is not None:
00440 self.log('Aborting pretest')
00441 self.prestartup_finished(script_timeout(0))
00442 return
00443
00444 if self._shutdown_launch is not None:
00445 self.log('Aborting shutdown script')
00446 self.shutdown_finished(script_timeout(0))
00447
00448 wx.MessageBox('No subtests, shutdown scripts or pretests to abort. Press the "Cancel" button to terminate test', 'Unable to abort', wx.OK)
00449
00450
00451 def set_test_host(self):
00452 curr_host = os.environ['ROS_TEST_HOST']
00453
00454 while not rospy.is_shutdown():
00455 host = wx.GetTextFromUser('Enter test host', 'Test Host', curr_host)
00456
00457 if host == '':
00458 wx.MessageBox('Host name unchanged. Current hostname: "%s".' % curr_host, 'Test Host Unchanged', wx.OK)
00459 break
00460
00461 try:
00462 machine_addr = socket.gethostbyname(host)
00463 os.environ['ROS_TEST_HOST'] = host
00464 break
00465 except socket.gaierror:
00466 wx.MessageBox('Hostname %s is invalid. Try again or click "Cancel".' % host, 'Test Host Invalid', wx.OK)
00467
00468 def load_wg_test_map(self):
00469 wgstations = {}
00470 load_ok = load_wg_station_map(wgstations)
00471
00472 gui_name = socket.gethostname()
00473
00474
00475 rospy.set_param('/qualification/powerboard/serial', '0000')
00476 rospy.set_param('/qualification/powerboard/0', False)
00477 rospy.set_param('/qualification/powerboard/1', False)
00478 rospy.set_param('/qualification/powerboard/2', False)
00479 os.environ['ROS_TEST_HOST'] = gui_name
00480
00481 if not load_ok:
00482 wx.MessageBox('Error: Unable to parse \'qualification/wg_map.xml\'. Please check the document and retry.','Unable to parse configuration', wx.OK|wx.ICON_ERROR, self)
00483
00484 return False
00485
00486 if not gui_name in wgstations:
00487 wx.MessageBox('Warning: Host %s not found in list of known hosts. Check file: \'qualification/wg_map.xml\'. You may be unable to run certain qualification tests' % gui_name,'Host not found', wx.OK|wx.ICON_ERROR, self)
00488 return False
00489
00490 my_station = wgstations[gui_name]
00491 rospy.set_param('/qualification/powerboard/serial', my_station.powerboard)
00492 rospy.set_param('/qualification/powerboard/0', my_station.breaker0)
00493 rospy.set_param('/qualification/powerboard/1', my_station.breaker1)
00494 rospy.set_param('/qualification/powerboard/2', my_station.breaker2)
00495
00496 my_station.set_envs()
00497
00498 try:
00499 machine_addr = socket.gethostbyname(my_station.test_host)
00500 os.environ['ROS_TEST_HOST'] = my_station.test_host
00501 except socket.gaierror:
00502 wx.MessageBox('Unable to resolve remote test host %s. The file: \'qualification/wg_map.xml\' may be invalid.' % my_station.test_host, 'Remote Host Not Found', wx.OK|wx.ICON_ERROR, self)
00503 return False
00504
00505 return True
00506
00507
00508
00509
00510
00511
00512
00513
00514