def start_dut_ping_process(self, iperf_server_on_ap, ip_version=IPV4): """Creates a process that pings the AP from the DUT. Runs in parallel for 15 seconds, so it can be interrupted by a reboot. Sleeps for a few seconds to ensure pings have started. Args: iperf_server_on_ap: IPerfServer object, linked to AP ip_version: string, the ip version (ipv4 or ipv6) """ ap_address = self.get_iperf_server_address(iperf_server_on_ap, ip_version) if ap_address: self.log.info( 'Starting ping process to %s in parallel. Logs from this ' 'process will be suppressed, since it will be intentionally ' 'interrupted.' % ap_address) ping_proc = Process(target=self.dut.ping, args=[ap_address], kwargs={'count': 15}) with utils.SuppressLogOutput(): ping_proc.start() # Allow for a few seconds of pinging before allowing it to be # interrupted. time.sleep(3) else: raise ConnectionError('Failed to retrieve APs iperf address.')
def import_test_modules(self, test_paths): """Imports test classes from test scripts. 1. Locate all .py files under test paths. 2. Import the .py files as modules. 3. Find the module members that are test classes. 4. Categorize the test classes by name. Args: test_paths: A list of directory paths where the test files reside. Returns: A dictionary where keys are test class name strings, values are actual test classes that can be instantiated. """ def is_testfile_name(name, ext): if ext == '.py': if name.endswith('Test') or name.endswith('_test'): return True return False file_list = utils.find_files(test_paths, is_testfile_name) test_classes = {} for path, name, _ in file_list: sys.path.append(path) try: with utils.SuppressLogOutput( log_levels=[logging.INFO, logging.ERROR]): module = importlib.import_module(name) except Exception as e: logging.debug('Failed to import %s: %s', path, str(e)) for test_cls_name, _ in self.run_list: alt_name = name.replace('_', '').lower() alt_cls_name = test_cls_name.lower() # Only block if a test class on the run list causes an # import error. We need to check against both naming # conventions: AaaBbb and aaa_bbb. if name == test_cls_name or alt_name == alt_cls_name: msg = ('Encountered error importing test class %s, ' 'abort.') % test_cls_name # This exception is logged here to help with debugging # under py2, because "raise X from Y" syntax is only # supported under py3. self.log.exception(msg) raise ValueError(msg) continue for member_name in dir(module): if not member_name.startswith('__'): if member_name.endswith('Test'): test_class = getattr(module, member_name) if inspect.isclass(test_class): test_classes[member_name] = test_class return test_classes
def test_suppress_log_output(self): """Tests that the SuppressLogOutput context manager removes handlers of the specified levels upon entry and re-adds handlers upon exit. """ handlers = [ logging.NullHandler(level=lvl) for lvl in (logging.DEBUG, logging.INFO, logging.ERROR) ] log = logging.getLogger('test_log') for handler in handlers: log.addHandler(handler) with utils.SuppressLogOutput(log, [logging.INFO, logging.ERROR]): self.assertTrue( any(handler.level == logging.DEBUG for handler in log.handlers)) self.assertFalse( any(handler.level in (logging.INFO, logging.ERROR) for handler in log.handlers)) self.assertCountEqual(handlers, log.handlers)
def reboot(self, use_ssh=False, unreachable_timeout=30, ping_timeout=30, ssh_timeout=30, reboot_type=FUCHSIA_REBOOT_TYPE_SOFT, testbed_pdus=None): """Reboot a FuchsiaDevice. Soft reboots the device, verifies it becomes unreachable, then verfifies it comes back online. Reinitializes SL4F so the tests can continue. Args: use_ssh: bool, if True, use fuchsia shell command via ssh to reboot instead of SL4F. unreachable_timeout: int, time to wait for device to become unreachable. ping_timeout: int, time to wait for device to respond to pings. ssh_timeout: int, time to wait for device to be reachable via ssh. reboot_type: boolFUCHSIA_REBOOT_TYPE_SOFT or FUCHSIA_REBOOT_TYPE_HARD testbed_pdus: list, all testbed PDUs Raises: ConnectionError, if device fails to become unreachable, fails to come back up, or if SL4F does not setup correctly. """ # Call Reboot if reboot_type == FUCHSIA_REBOOT_TYPE_SOFT: if use_ssh: self.log.info('Sending reboot command via SSH.') with utils.SuppressLogOutput(): self.clean_up() self.send_command_ssh( 'dm reboot', timeout=FUCHSIA_RECONNECT_AFTER_REBOOT_TIME, skip_status_code_check=True) else: self.log.info('Initializing reboot of FuchsiaDevice (%s)' ' with SL4F.' % self.ip) self.log.info('Calling SL4F reboot command.') with utils.SuppressLogOutput(): if self.log_process: self.log_process.stop() self.hardware_power_statecontrol_lib.suspendReboot( timeout=3) if self._persistent_ssh_conn: self._persistent_ssh_conn.close() self._persistent_ssh_conn = None elif reboot_type == FUCHSIA_REBOOT_TYPE_HARD: self.log.info('Power cycling FuchsiaDevice (%s)' % self.ip) device_pdu, device_pdu_port = pdu.get_pdu_port_for_device( self.device_pdu_config, testbed_pdus) with utils.SuppressLogOutput(): if self.log_process: self.log_process.stop() if self._persistent_ssh_conn: self._persistent_ssh_conn.close() self._persistent_ssh_conn = None self.log.info('Killing power to FuchsiaDevice (%s)...' % self.ip) device_pdu.off(str(device_pdu_port)) # Wait for unreachable self.log.info('Verifying device is unreachable.') timeout = time.time() + unreachable_timeout while (time.time() < timeout): if utils.is_pingable(self.ip): self.log.debug('Device is still pingable. Retrying.') else: if reboot_type == FUCHSIA_REBOOT_TYPE_HARD: self.log.info('Restoring power to FuchsiaDevice (%s)...' % self.ip) device_pdu.on(str(device_pdu_port)) break else: self.log.info('Device failed to go offline. Reintializing Sl4F.') self.start_services() self.init_server_connection() raise ConnectionError('Device never went down.') self.log.info('Device is unreachable as expected.') if reboot_type == FUCHSIA_REBOOT_TYPE_HARD: self.log.info('Restoring power to FuchsiaDevice (%s)...' % self.ip) device_pdu.on(str(device_pdu_port)) self.log.info('Waiting for device to respond to pings.') self.verify_ping(timeout=ping_timeout) self.log.info('Device responded to pings.') self.log.info('Waiting for device to allow ssh connection.') self.verify_ssh(timeout=ssh_timeout) self.log.info('Device now available via ssh.') # Creating new log process, start it, start new persistent ssh session, # start SL4F, and connect via SL4F self.log.info( 'Restarting log process and reinitiating SL4F on FuchsiaDevice %s' % self.ip) self.log_process.start() self.start_services() # Verify SL4F is up. self.log.info( 'Initiating connection to SL4F and verifying commands can run.') try: self.init_server_connection() self.hwinfo_lib.getDeviceInfo() except Exception as err: raise ConnectionError( 'Failed to connect and run command via SL4F. Err: %s' % err) self.log.info( 'Device has rebooted, SL4F is reconnected and functional.')
def _run_traffic(self, uuid, client, server_ip, server_port, active_streams, stream_results, access_category=None, bandwidth=None, stream_time=DEFAULT_STREAM_TIME, start_time=None): """Runs an iperf3 stream. 1. Adds stream UUID to active_streams 2. Runs stream 3. Saves results to stream_results 4. Removes stream UUID from active_streams Args: uuid: UUID object, identifier for stream client: IPerfClient object on device server_ip: string, ip address of IPerfServer for stream server_port: int, port of the IPerfServer for stream active_streams: multiprocessing.Manager.dict, which holds stream UUIDs of active streams on the device stream_results: multiprocessing.Manager.dict, which maps stream UUIDs of streams to IPerfResult objects access_category: string, WMM access category to use with iperf (AC_BK, AC_BE, AC_VI, AC_VO). Unset if None. bandwidth: int, bandwidth in mbps to use with iperf. Implies UDP. Unlimited if None. stream_time: int, time in seconds, to run iperf stream start_time: float, time, seconds since epoch, at which to start the stream (for better synchronicity). If None, start immediately. """ active_streams[uuid] = True # SSH sessions must be started within the process that is going to # use it. if type(client) == iperf_client.IPerfClientOverSsh: with utils.SuppressLogOutput(): client.start_ssh() ac_flag = '' bandwidth_flag = '' time_flag = '-t %s' % stream_time if access_category: ac_flag = ' -S %s' % DEFAULT_AC_TO_TOS_TAG_MAP[access_category] if bandwidth: bandwidth_flag = ' -u -b %sM' % bandwidth iperf_flags = '-p %s -i 1 %s%s%s -J' % (server_port, time_flag, ac_flag, bandwidth_flag) if not start_time: start_time = time.time() time_str = datetime.fromtimestamp(start_time).strftime('%H:%M:%S.%f') self.log.info( 'At %s, starting %s second stream to %s:%s with (AC: %s, Bandwidth: %s)' % (time_str, stream_time, server_ip, server_port, access_category, bandwidth if bandwidth else 'Unlimited')) # If present, wait for stream start time if start_time: current_time = time.time() while current_time < start_time: current_time = time.time() path = client.start(server_ip, iperf_flags, '%s' % uuid) stream_results[uuid] = iperf_server.IPerfResult( path, reporting_speed_units='mbps') if type(client) == iperf_client.IPerfClientOverSsh: client.close_ssh() active_streams.pop(uuid)