def _wait_dialog(self): """Wait for dialogs and handle them until done. """ logger.debug('waiting for dialog') done = False error = False logger.info("self timeout %d",self.timeout) while not done and self.timeout: try: dialog = self._browser.find_element_by_id('RemoteConfirm') except: logger.exception('Failed to get dialog.') else: if dialog and dialog.get_attribute('aria-hidden') == 'false': title = dialog.find_element_by_class_name('modal-title').text time.sleep(1) logger.info('Handling dialog[%s]', title) try: done = self._handle_dialog(dialog, title) except: logger.exception('Error handling dialog: %s', title) error = True if done is None: raise FailError('Unexpected dialog occurred') dialog.find_element_by_id('ConfirmOk').click() time.sleep(1) try: stop_button = self._browser.find_element_by_id('stopTest') if done: stop_button.click() # wait for stop procedure end time.sleep(10) except NoSuchElementException: logger.info('Test stopped') time.sleep(5) done = True self.timeout -= 1 # check if already ended capture if self.timeout % 10 == 0: lines = self._hc.tail() if 'SUCCESS: The process "dumpcap.exe" with PID ' in lines: logger.info('Tshark should be ended now, lets wait at most 30 seconds.') if not wait_until(lambda: 'tshark.exe' not in subprocess.check_output('tasklist'), 30): res = subprocess.check_output('taskkill /t /f /im tshark.exe', stderr=subprocess.STDOUT, shell=True) logger.info(res) # Wait until case really stopped wait_until(lambda: self._browser.find_element_by_id('runTest') and True, 30) if error: raise FailError('Fail for previous exceptions')
def _init_harness(self): """Restart harness backend service. Please start the harness controller before running the cases, otherwise, nothing happens """ self._hc = HarnessController(self.result_dir) self._hc.stop() time.sleep(1) self._hc.start() time.sleep(2) harness_config = ConfigParser.ConfigParser() harness_config.read('%s\\Config\\Configuration.ini' % settings.HARNESS_HOME) if harness_config.has_option( 'THREAD_HARNESS_CONFIG', 'BrowserAutoNavigate') and harness_config.getboolean( 'THREAD_HARNESS_CONFIG', 'BrowserAutoNavigate'): logger.error( 'BrowserAutoNavigate in Configuration.ini should be False') raise FailError( 'BrowserAutoNavigate in Configuration.ini should be False') if settings.MIXED_DEVICE_TYPE: if harness_config.has_option( 'THREAD_HARNESS_CONFIG', 'EnableDeviceSelection') and not harness_config.getboolean( 'THREAD_HARNESS_CONFIG', 'EnableDeviceSelection'): logger.error( 'EnableDeviceSelection in Configuration.ini should be True' ) raise FailError( 'EnableDeviceSelection in Configuration.ini should be True' )
def _handle_dialog(self, dialog, title): """Handle a dialog. Returns: bool True if no more dialogs expected, False if more dialogs needed, and None if not handled """ done = self.on_dialog(dialog, title) if isinstance(done, bool): return done if title.startswith('Start DUT'): body = dialog.find_element_by_id('cnfrmMsg').text if 'Sleepy End Device' in body: self.dut.mode = 's' self.dut.child_timeout = self.child_timeout elif 'End Device' in body: self.dut.mode = 'rsn' self.dut.child_timeout = self.child_timeout else: self.dut.mode = 'rsdn' if 'at channel' in body: self.channel = int(body.split(':')[1]) self.dut.channel = self.channel self.dut.panid = settings.THREAD_PANID self.dut.networkname = settings.THREAD_NETWORKNAME self.dut.extpanid = settings.THREAD_EXTPANID self.dut.start() elif title.startswith('MAC Address Required') or title.startswith('DUT Random Extended MAC Address Required'): mac = self.dut.mac inp = dialog.find_element_by_id('cnfrmInpText') inp.clear() inp.send_keys('0x%s' % mac) elif title.startswith('LL64 Address'): ll64 = None for addr in self.dut.addrs: addr = addr.lower() if addr.startswith('fe80') and not re.match('.+ff:fe00:[0-9a-f]{0,4}$', addr): ll64 = addr break if not ll64: raise FailError('No link local address found') logger.info('Link local address is %s', ll64) inp = dialog.find_element_by_id('cnfrmInpText') inp.clear() inp.send_keys(ll64) elif title.startswith('Enter Channel'): self.dut.channel = self.channel inp = dialog.find_element_by_id('cnfrmInpText') inp.clear() inp.send_keys(str(self.dut.channel)) elif title.startswith('User Action Needed'): body = dialog.find_element_by_id('cnfrmMsg').text if body.startswith('Power Down the DUT'): self.dut.stop() return True elif title.startswith('Short Address'): short_addr = '0x%s' % self.dut.short_addr inp = dialog.find_element_by_id('cnfrmInpText') inp.clear() inp.send_keys(short_addr) elif title.startswith('ML64 Address'): ml64 = None for addr in self.dut.addrs: if addr.startswith('fd') and not re.match('.+ff:fe00:[0-9a-f]{0,4}$', addr): ml64 = addr break if not ml64: raise Exception('No mesh local address found') logger.info('Mesh local address is %s', ml64) inp = dialog.find_element_by_id('cnfrmInpText') inp.clear() inp.send_keys(ml64) elif title.startswith('Shield Devices') or title.startswith('Shield DUT'): time.sleep(2) if self.rf_shield: logger.info('Shielding devices') with self.rf_shield: self.rf_shield.shield() elif self.dut and settings.SHIELD_SIMULATION: self.dut.channel = (self.channel == THREAD_CHANNEL_MAX and THREAD_CHANNEL_MIN) or (self.channel + 1) else: input('Shield DUT and press enter to continue..') elif title.startswith('Unshield Devices') or title.startswith('Bring DUT back to network'): time.sleep(5) if self.rf_shield: logger.info('Unshielding devices') with self.rf_shield: self.rf_shield.unshield() elif self.dut and settings.SHIELD_SIMULATION: self.dut.channel = self.channel else: input('Bring DUT and press enter to continue..') elif title.startswith('Configure Prefix on DUT'): body = dialog.find_element_by_id('cnfrmMsg').text body = body.split(': ')[1] params = reduce( lambda params, param: params.update(((param[0].strip(' '), param[1]),)) or params, [it.split('=') for it in body.split(', ')], {}, ) prefix = params['P_Prefix'].strip('\0\r\n\t ') flags = [] if params.get('P_slaac_preferred', 0) == '1': flags.append('p') flags.append('ao') if params.get('P_stable', 0) == '1': flags.append('s') if params.get('P_default', 0) == '1': flags.append('r') prf = 'high' self.dut.add_prefix(prefix, ''.join(flags), prf) return False
def _test_bed(self): """Set up the test bed. Connect number of golden devices required by each case. """ browser = self._browser test_bed = browser.find_element_by_id('test-bed') time.sleep(3) selected_hw_set = test_bed.find_elements_by_class_name('selected-hw') selected_hw_num = len(selected_hw_set) while selected_hw_num: remove_button = selected_hw_set[selected_hw_num - 1].find_element_by_class_name('removeSelectedDevice') remove_button.click() selected_hw_num = selected_hw_num - 1 devices = [ device for device in settings.GOLDEN_DEVICES if not self.history.is_bad_golden_device(device[0]) and not (settings.DUT_DEVICE and device[0] == settings.DUT_DEVICE[0]) ] logger.info('Available golden devices: %s', json.dumps(devices, indent=2)) shield_devices = [ shield_device for shield_device in settings.SHIELD_GOLDEN_DEVICES if not self.history.is_bad_golden_device(shield_device[0]) and not (settings.DUT2_DEVICE and shield_device[0] == settings.DUT2_DEVICE[0]) ] logger.info('Available shield golden devices: %s', json.dumps(shield_devices, indent=2)) golden_devices_required = self.golden_devices_required dut_device = () if settings.DUT_DEVICE: dut_device = settings.DUT_DEVICE """check if test case needs to use RF-shield box and its device order in Testbed page Two parameters case_need_shield & device_order should be set in the case script according to the requires: https://openthread.io/certification/test-cases#rf_shielding Example: In case script leader_9_2_9.py: case_need_shield = True device_order = [('Router_2', False), ('Commissioner', True), ('Router_1', False), ('DUT', True)] On the TestBed page of the Test Harness, the device sort order for Leader_9_2_9 should be like: Router_2 Commissioner Router_1 DUT The ('Commissioner', True) and ('DUT', True) indicate Commissioner device and DUT2 device should be in the RF-box and choose from SHIELD_GOLDEN_DEVICES and DUT2_DEVICE. Otherwise ('DUT', False) means DUT device is not in RF-box and use DUT_DEVICE. The other roles devices with False should be selected from GOLDEN_DEVICES. In case script med_6_3_2.py: case_need_shield = True device_order = [] # or not defined means no device drag order. DUT2_DEVICE should be applied as DUT and the other golden devices are from GOLDEN_DEVICES. """ if self.case_need_shield: if not settings.DUT2_DEVICE: logger.info('Must set DUT2_DEVICE') raise FailError('DUT2_DEVICE must be set in settings.py') if isinstance(self.device_order, list) and self.device_order: logger.info('case %s devices ordered by %s ', self.case, self.device_order) else: logger.info('case %s uses %s as DUT', self.case, settings.DUT2_DEVICE) # for test bed with multi-vendor devices if settings.MIXED_DEVICE_TYPE: topo_file = settings.HARNESS_HOME + "\\Thread_Harness\\TestScripts\\TopologyConfig.txt" try: f_topo = open(topo_file, 'r') except IOError: logger.info('%s can NOT be found', topo_file) raise GoldenDeviceNotEnoughError() topo_mixed_devices = [] try: while True: topo_line = f_topo.readline().strip() if re.match(r'#.*', topo_line): continue match_line = re.match(r'(.*)-(.*)', topo_line, re.M | re.I) if not match_line: continue case_id = match_line.group(1) if re.sub(r'\.', ' ', case_id) == self.case: logger.info('Get line by case %s: %s', case_id, topo_line) topo_device_list = re.split(',', match_line.group(2)) for i in range(len(topo_device_list)): topo_device = re.split(':', topo_device_list[i]) topo_mixed_devices.append(tuple(topo_device)) break else: continue except Exception as e: logger.info('Get devices from topology config file error: %s', e) raise GoldenDeviceNotEnoughError() logger.info('Golden devices in topology config file for case %s: %s', case_id, topo_mixed_devices) f_topo.close() golden_device_candidates = [] missing_golden_devices = topo_mixed_devices[:] # mapping topology config devices with golden devices by device order if self.case_need_shield and self.device_order: matched_dut = False for device_order_item in self.device_order: matched = False for mixed_device_item in topo_mixed_devices: # mapping device in device_order which needs to be shielded if device_order_item[1]: if 'DUT' in device_order_item[0]: golden_device_candidates.append(settings.DUT2_DEVICE) dut_device = settings.DUT2_DEVICE matched_dut = True matched = True break for device_item in shield_devices: if ( device_order_item[0] == mixed_device_item[0] and mixed_device_item[1] == device_item[1] ): golden_device_candidates.append(device_item) shield_devices.remove(device_item) matched = True break # mapping device in device_order which does not need to be shielded else: if 'DUT' in device_order_item[0]: golden_device_candidates.append(settings.DUT_DEVICE) matched_dut = True matched = True break for device_item in devices: if ( device_order_item[0] == mixed_device_item[0] and mixed_device_item[1] == device_item[1] ): golden_device_candidates.append(device_item) devices.remove(device_item) matched = True break if not matched: logger.info('Golden device not enough in : no %s', device_order_item) raise GoldenDeviceNotEnoughError() if not matched_dut: raise FailError('Failed to find DUT in device_order') devices = golden_device_candidates self.add_all_devices = True else: for mixed_device_item in topo_mixed_devices: for device_item in devices: if mixed_device_item[1] == device_item[1]: golden_device_candidates.append(device_item) devices.remove(device_item) missing_golden_devices.remove(mixed_device_item) break logger.info('Golden devices in topology config file mapped in settings : %s', golden_device_candidates) if len(topo_mixed_devices) != len(golden_device_candidates): device_dict = dict() for missing_device in missing_golden_devices: if missing_device[1] in device_dict: device_dict[missing_device[1]] += 1 else: device_dict[missing_device[1]] = 1 logger.info('Missing Devices: %s', device_dict) raise GoldenDeviceNotEnoughError() else: devices = golden_device_candidates golden_devices_required = len(devices) logger.info('All case-needed golden devices: %s', json.dumps(devices, indent=2)) # for test bed with single vendor devices else: golden_device_candidates = [] if self.case_need_shield and self.device_order: matched_dut = False for device_order_item in self.device_order: matched = False # choose device which needs to be shielded if device_order_item[1]: if 'DUT' in device_order_item[0]: golden_device_candidates.append(settings.DUT2_DEVICE) dut_device = settings.DUT2_DEVICE matched_dut = True matched = True else: for device_item in shield_devices: golden_device_candidates.append(device_item) shield_devices.remove(device_item) matched = True break # choose device which does not need to be shielded else: if 'DUT' in device_order_item[0]: golden_device_candidates.append(settings.DUT_DEVICE) matched_dut = True matched = True else: for device_item in devices: golden_device_candidates.append(device_item) devices.remove(device_item) matched = True break if not matched: logger.info('Golden device not enough in : no %s', device_order_item) raise GoldenDeviceNotEnoughError() if not matched_dut: raise FailError('Failed to find DUT in device_order') devices = golden_device_candidates self.add_all_devices = True if self.auto_dut and not settings.DUT_DEVICE: if settings.MIXED_DEVICE_TYPE: logger.info('Must set DUT_DEVICE') raise FailError('DUT_DEVICE must be set for mixed testbed') golden_devices_required += 1 if len(devices) < golden_devices_required: raise GoldenDeviceNotEnoughError() # add golden devices number_of_devices_to_add = len(devices) if self.add_all_devices else golden_devices_required for i in range(number_of_devices_to_add): self._add_device(*devices.pop()) # add DUT if self.case_need_shield: if not self.device_order: self._add_device(*settings.DUT2_DEVICE) else: if settings.DUT_DEVICE: self._add_device(*settings.DUT_DEVICE) # enable AUTO DUT if self.auto_dut: checkbox_auto_dut = browser.find_element_by_id('EnableAutoDutSelection') if not checkbox_auto_dut.is_selected(): checkbox_auto_dut.click() time.sleep(1) if settings.DUT_DEVICE: radio_auto_dut = browser.find_element_by_class_name('AutoDUT_RadBtns') if not radio_auto_dut.is_selected() and not self.device_order: radio_auto_dut.click() if self.device_order: selected_hw_set = test_bed.find_elements_by_class_name('selected-hw') for selected_hw in selected_hw_set: form_inputs = selected_hw.find_elements_by_tag_name('input') form_port = form_inputs[0] port = form_port.get_attribute('value').encode('utf8') if port == dut_device[0]: radio_auto_dut = selected_hw.find_element_by_class_name('AutoDUT_RadBtns') if not radio_auto_dut.is_selected(): radio_auto_dut.click() while True: try: self._connect_devices() button_next = browser.find_element_by_id('nextBtn') if not wait_until( lambda: 'disabled' not in button_next.get_attribute('class'), times=(30 + 4 * number_of_devices_to_add), ): bad_ones = [] selected_hw_set = test_bed.find_elements_by_class_name('selected-hw') for selected_hw in selected_hw_set: form_inputs = selected_hw.find_elements_by_tag_name('input') form_port = form_inputs[0] if form_port.is_enabled(): bad_ones.append(selected_hw) for selected_hw in bad_ones: form_inputs = selected_hw.find_elements_by_tag_name('input') form_port = form_inputs[0] port = form_port.get_attribute('value').encode('utf8') if port == dut_device[0]: if settings.PDU_CONTROLLER_TYPE is None: # connection error cannot recover without power # cycling raise FatalError('Failed to connect to DUT') else: raise FailError('Failed to connect to DUT') if settings.PDU_CONTROLLER_TYPE is None: # port cannot recover without power cycling self.history.mark_bad_golden_device(port) # remove the bad one selected_hw.find_element_by_class_name('removeSelectedDevice').click() time.sleep(0.1) if len(devices): self._add_device(*devices.pop()) else: devices = None if devices is None: logger.warning('Golden devices not enough') raise GoldenDeviceNotEnoughError() else: logger.info('Try again with new golden devices') continue if self.auto_dut and not settings.DUT_DEVICE: radio_auto_dut = browser.find_element_by_class_name('AutoDUT_RadBtns') if not radio_auto_dut.is_selected(): radio_auto_dut.click() time.sleep(5) button_next.click() if not wait_until(lambda: self._browser.current_url.endswith('TestExecution.html'), 20): raise Exception('Failed to load TestExecution page') except FailError: raise except BaseException: logger.exception('Unexpected error') else: break
def _test_bed(self): """Set up the test bed. Connect number of golden devices required by each case. """ browser = self._browser test_bed = browser.find_element_by_id('test-bed') time.sleep(3) selected_hw_set = test_bed.find_elements_by_class_name('selected-hw') selected_hw_num = len(selected_hw_set) while selected_hw_num: remove_button = selected_hw_set[selected_hw_num - 1].find_element_by_class_name( 'removeSelectedDevice') remove_button.click() selected_hw_num = selected_hw_num - 1 devices = [device for device in settings.GOLDEN_DEVICES if not self.history.is_bad_golden_device(device[0]) and \ not (settings.DUT_DEVICE and device[0] == settings.DUT_DEVICE[0])] logger.info('Available golden devices: %s', json.dumps(devices, indent=2)) golden_devices_required = self.golden_devices_required # for test bed with mixed devices if settings.MIXED_DEVICE_TYPE: topo_file = settings.HARNESS_HOME+"\\Thread_Harness\\TestScripts\\TopologyConfig.txt" try: f_topo = open(topo_file, 'r') except IOError as e: logger.info('%s can NOT be found', topo_file) raise GoldenDeviceNotEnoughError() topo_mixed_devices = [] try: while 1: topo_line = f_topo.readline().strip() match_line = re.match(r'(.*)-(.*)', topo_line, re.M | re.I) case_id = match_line.group(1) if re.sub(r'\.', ' ', case_id) == self.case: logger.info('Get line by case %s: %s', case_id, topo_line) topo_device_list = re.split(',', match_line.group(2)) for i in range(len(topo_device_list)): topo_device = re.split(':', topo_device_list[i]) topo_mixed_devices.append(tuple(topo_device)) break else: continue except Exception as e: logger.info('Get devices from topology config file error: %s', e) raise GoldenDeviceNotEnoughError() logger.info('Golden devices in topology config file for case %s: %s', case_id, topo_mixed_devices) f_topo.close() golden_device_candidates = [] missing_golden_devices = topo_mixed_devices[:] # mapping topology config devices with devices in settings for mixed_device_item in topo_mixed_devices: for device_item in devices: if mixed_device_item[1] == device_item[1]: golden_device_candidates.append(device_item) devices.remove(device_item) missing_golden_devices.remove(mixed_device_item) break logger.info('Golden devices in topology config file mapped in settings : %s', golden_device_candidates) if len(topo_mixed_devices) != len(golden_device_candidates): device_dict = dict() for missing_device in missing_golden_devices: if missing_device[1] in device_dict: device_dict[missing_device[1]] += 1 else: device_dict[missing_device[1]] = 1 logger.info('Missing Devices: %s', device_dict) raise GoldenDeviceNotEnoughError() else: devices = golden_device_candidates golden_devices_required = len(devices) logger.info('All case-needed golden devices: %s', json.dumps(devices, indent=2)) if self.auto_dut and not settings.DUT_DEVICE: if settings.MIXED_DEVICE_TYPE: logger.info('Must set DUT_DEVICE') raise FailError('DUT_DEVICE must be set for mixed testbed') golden_devices_required += 1 if len(devices) < golden_devices_required: raise GoldenDeviceNotEnoughError() # add golden devices number_of_devices_to_add = len(devices) if self.add_all_devices else golden_devices_required for i in range(number_of_devices_to_add): self._add_device(*devices.pop()) # add DUT if settings.DUT_DEVICE: self._add_device(*settings.DUT_DEVICE) # enable AUTO DUT if self.auto_dut: checkbox_auto_dut = browser.find_element_by_id('EnableAutoDutSelection') if not checkbox_auto_dut.is_selected(): checkbox_auto_dut.click() time.sleep(1) if settings.DUT_DEVICE: radio_auto_dut = browser.find_element_by_class_name('AutoDUT_RadBtns') if not radio_auto_dut.is_selected(): radio_auto_dut.click() while True: try: self._connect_devices() button_next = browser.find_element_by_id('nextBtn') if not wait_until(lambda: 'disabled' not in button_next.get_attribute('class'), times=(30 + 4 * number_of_devices_to_add)): bad_ones = [] selected_hw_set = test_bed.find_elements_by_class_name('selected-hw') for selected_hw in selected_hw_set: form_inputs = selected_hw.find_elements_by_tag_name('input') form_port = form_inputs[0] if form_port.is_enabled(): bad_ones.append(selected_hw) for selected_hw in bad_ones: form_inputs = selected_hw.find_elements_by_tag_name('input') form_port = form_inputs[0] port = form_port.get_attribute('value').encode('utf8') if settings.DUT_DEVICE and port == settings.DUT_DEVICE[0]: if settings.PDU_CONTROLLER_TYPE is None: # connection error cannot recover without power cycling raise FatalError('Failed to connect to DUT') else: raise FailError('Failed to connect to DUT') if settings.PDU_CONTROLLER_TYPE is None: # port cannot recover without power cycling self.history.mark_bad_golden_device(port) # remove the bad one selected_hw.find_element_by_class_name('removeSelectedDevice').click() time.sleep(0.1) if len(devices): self._add_device(*devices.pop()) else: devices = None if devices is None: logger.warning('Golden devices not enough') raise GoldenDeviceNotEnoughError() else: logger.info('Try again with new golden devices') continue if self.auto_dut and not settings.DUT_DEVICE: radio_auto_dut = browser.find_element_by_class_name('AutoDUT_RadBtns') if not radio_auto_dut.is_selected(): radio_auto_dut.click() time.sleep(5) button_next.click() if not wait_until(lambda: self._browser.current_url.endswith('TestExecution.html'), 20): raise Exception('Failed to load TestExecution page') except FailError: raise except: logger.exception('Unexpected error') else: break
def _test_bed(self): """Set up the test bed. Connect number of golden devices required by each case. """ browser = self._browser test_bed = browser.find_element_by_id('test-bed') time.sleep(3) selected_hw_set = test_bed.find_elements_by_class_name('selected-hw') selected_hw_num = len(selected_hw_set) while selected_hw_num: remove_button = selected_hw_set[selected_hw_num - 1].find_element_by_class_name( 'removeSelectedDevice') remove_button.click() selected_hw_num = selected_hw_num - 1 devices = [device for device in settings.GOLDEN_DEVICES if not self.history.is_bad_golden_device(device[0]) and \ not (settings.DUT_DEVICE and device[0] == settings.DUT_DEVICE[0])] logger.info('Available golden devices: %s', json.dumps(devices, indent=2)) golden_devices_required = self.golden_devices_required if self.auto_dut and not settings.DUT_DEVICE: golden_devices_required += 1 if len(devices) < golden_devices_required: raise GoldenDeviceNotEnoughError() # add golden devices while golden_devices_required: self._add_device(*devices.pop()) golden_devices_required = golden_devices_required - 1 # add DUT if settings.DUT_DEVICE: self._add_device(*settings.DUT_DEVICE) # enable AUTO DUT if self.auto_dut: checkbox_auto_dut = browser.find_element_by_id('EnableAutoDutSelection') if not checkbox_auto_dut.is_selected(): checkbox_auto_dut.click() time.sleep(1) if settings.DUT_DEVICE: radio_auto_dut = browser.find_element_by_class_name('AutoDUT_RadBtns') if not radio_auto_dut.is_selected(): radio_auto_dut.click() while True: try: self._connect_devices() button_next = browser.find_element_by_id('nextBtn') if not wait_until(lambda: 'disabled' not in button_next.get_attribute('class'), times=(30 + 4 * self.golden_devices_required)): bad_ones = [] selected_hw_set = test_bed.find_elements_by_class_name('selected-hw') for selected_hw in selected_hw_set: form_inputs = selected_hw.find_elements_by_tag_name('input') form_port = form_inputs[0] if form_port.is_enabled(): bad_ones.append(selected_hw) for selected_hw in bad_ones: form_inputs = selected_hw.find_elements_by_tag_name('input') form_port = form_inputs[0] port = form_port.get_attribute('value').encode('utf8') if settings.DUT_DEVICE and port == settings.DUT_DEVICE[0]: if settings.PDU_CONTROLLER_TYPE is None: # connection error cannot recover without power cycling raise FatalError('Failed to connect to DUT') else: raise FailError('Failed to connect to DUT') if settings.PDU_CONTROLLER_TYPE is None: # port cannot recover without power cycling self.history.mark_bad_golden_device(port) # remove the bad one selected_hw.find_element_by_class_name('removeSelectedDevice').click() time.sleep(0.1) if len(devices): self._add_device(*devices.pop()) else: devices = None if devices is None: logger.warning('Golden devices not enough') raise GoldenDeviceNotEnoughError() else: logger.info('Try again with new golden devices') continue if self.auto_dut and not settings.DUT_DEVICE: radio_auto_dut = browser.find_element_by_class_name('AutoDUT_RadBtns') if not radio_auto_dut.is_selected(): radio_auto_dut.click() time.sleep(5) button_next.click() except FailError: raise except: logger.exception('Unexpected error') else: break