예제 #1
0
    def __init__(self, test_configs, run_list):
        """Constructor for TestRunner.

        During construction, the input config_parser.TestRunConfig object is
        processed and populated with information specific to a test run. The
        config object is later passed to each test class for execution.

        Args:
            test_configs: A config_parser.TestRunConfig object.
            run_list:  A list of tuples specifying what tests to run.
        """
        self.test_run_info = None
        self.test_configs = test_configs
        test_bed_name = self.test_configs.test_bed_name
        start_time = logger.get_log_file_timestamp()
        self.id = '%s@%s' % (test_bed_name, start_time)
        # log_path should be set before parsing configs.
        l_path = os.path.join(self.test_configs.log_path, test_bed_name,
                              start_time)
        self.log_path = os.path.abspath(l_path)
        logger.setup_test_logger(self.log_path, test_bed_name)
        self.controller_registry = {}
        self.controller_destructors = {}
        self.run_list = run_list
        self.results = records.TestResult()
        self.running = False
        self.test_classes = {}
예제 #2
0
def take_bug_reports(ads, test_name=None, begin_time=None, destination=None):
  """Takes bug reports on a list of android devices.

  If you want to take a bug report, call this function with a list of
  android_device objects in on_fail. But reports will be taken on all the
  devices in the list concurrently. Bug report takes a relative long
  time to take, so use this cautiously.

  Args:
    ads: A list of AndroidDevice instances.
    test_name: Name of the test method that triggered this bug report.
      If None, the default name "bugreport" will be used.
    begin_time: timestamp taken when the test started, can be either
      string or int. If None, the current time will be used.
    destination: string, path to the directory where the bugreport
      should be saved.
  """
  if begin_time is None:
    begin_time = mobly_logger.get_log_file_timestamp()
  else:
    begin_time = mobly_logger.sanitize_filename(str(begin_time))

  def take_br(test_name, begin_time, ad, destination):
    ad.take_bug_report(test_name=test_name,
                       begin_time=begin_time,
                       destination=destination)

  args = [(test_name, begin_time, ad, destination) for ad in ads]
  utils.concurrent_exec(take_br, args)
예제 #3
0
    def take_bug_report(self,
                        test_name=None,
                        begin_time=None,
                        timeout=300,
                        destination=None):
        """Takes a bug report on the device and stores it in a file.

        Args:
            test_name: Name of the test method that triggered this bug report.
            begin_time: Timestamp of when the test started. If not set, then
                this will default to the current time.
            timeout: float, the number of seconds to wait for bugreport to
                complete, default is 5min.
            destination: string, path to the directory where the bugreport
                should be saved.

        Returns:
            A string that is the absolute path to the bug report on the host.
        """
        prefix = DEFAULT_BUG_REPORT_NAME
        if test_name:
            prefix = '%s,%s' % (DEFAULT_BUG_REPORT_NAME, test_name)
        if begin_time is None:
            begin_time = mobly_logger.get_log_file_timestamp()

        new_br = True
        try:
            stdout = self.adb.shell('bugreportz -v').decode('utf-8')
            # This check is necessary for builds before N, where adb shell's ret
            # code and stderr are not propagated properly.
            if 'not found' in stdout:
                new_br = False
        except adb.AdbError:
            new_br = False

        if destination is None:
            destination = os.path.join(self.log_path, 'BugReports')
        br_path = utils.abs_path(destination)
        utils.create_dir(br_path)
        filename = self.generate_filename(prefix, str(begin_time), 'txt')
        if new_br:
            filename = filename.replace('.txt', '.zip')
        full_out_path = os.path.join(br_path, filename)
        # in case device restarted, wait for adb interface to return
        self.wait_for_boot_completion()
        self.log.debug('Start taking bugreport.')
        if new_br:
            out = self.adb.shell('bugreportz', timeout=timeout).decode('utf-8')
            if not out.startswith('OK'):
                raise DeviceError(self, 'Failed to take bugreport: %s' % out)
            br_out_path = out.split(':')[1].strip()
            self.adb.pull([br_out_path, full_out_path])
        else:
            # shell=True as this command redirects the stdout to a local file
            # using shell redirection.
            self.adb.bugreport(' > "%s"' % full_out_path,
                               shell=True,
                               timeout=timeout)
        self.log.debug('Bugreport taken at %s.', full_out_path)
        return full_out_path
예제 #4
0
    def start_capture(self,
                      override_configs=None,
                      additional_args=None,
                      duration=None,
                      packet_count=None):
        """See base class documentation
        """
        if self._process is not None:
            raise sniffer.InvalidOperationError(
                "Trying to start a sniff while another is still running!")
        capture_dir = os.path.join(self._logger.log_path,
                                   "Sniffer-{}".format(self._interface))
        os.makedirs(capture_dir, exist_ok=True)
        self._capture_file_path = os.path.join(
            capture_dir,
            "capture_{}.pcap".format(logger.get_log_file_timestamp()))

        self._pre_capture_config(override_configs)
        _, self._temp_capture_file_path = tempfile.mkstemp(suffix=".pcap")

        cmd = self._get_command_line(additional_args=additional_args,
                                     duration=duration,
                                     packet_count=packet_count)

        self._process = utils.start_standing_subprocess(cmd)
        return sniffer.ActiveCaptureContext(self, duration)
예제 #5
0
    def run(self):
        """Executes tests.

        This will instantiate controller and test classes, execute tests, and
        print a summary.

        Raises:
            Error: if no tests have previously been added to this runner using
                add_test_class(...).
        """
        if not self._test_run_infos:
            raise Error('No tests to execute.')
        start_time = logger.get_log_file_timestamp()
        log_path = os.path.join(self._log_dir, self._test_bed_name, start_time)
        summary_writer = records.TestSummaryWriter(
            os.path.join(log_path, records.OUTPUT_FILE_SUMMARY))
        logger.setup_test_logger(log_path, self._test_bed_name)
        try:
            for test_run_info in self._test_run_infos:
                # Set up the test-specific config
                test_config = test_run_info.config.copy()
                test_config.log_path = log_path
                test_config.register_controller = functools.partial(
                    self._register_controller, test_config)
                test_config.summary_writer = summary_writer
                try:
                    self._run_test_class(test_config, test_run_info.test_class,
                                         test_run_info.tests)
                except signals.TestAbortAll as e:
                    logging.warning(
                        'Abort all subsequent test classes. Reason: %s', e)
                    raise
                finally:
                    self._unregister_controllers()
        finally:
            # Write controller info and summary to summary file.
            summary_writer.dump(self.results.controller_info,
                                records.TestSummaryEntryType.CONTROLLER_INFO)
            summary_writer.dump(self.results.summary_dict(),
                                records.TestSummaryEntryType.SUMMARY)
            # Stop and show summary.
            msg = '\nSummary for test run %s@%s: %s\n' % (
                self._test_bed_name, start_time, self.results.summary_str())
            self._write_results_json_str(log_path)
            logging.info(msg.strip())
            logger.kill_test_logger(logging.getLogger())
예제 #6
0
 def __init__(self, test_configs, run_list):
     self.test_run_info = {}
     self.test_configs = test_configs
     self.testbed_configs = self.test_configs[keys.Config.key_testbed.value]
     self.testbed_name = self.testbed_configs[
         keys.Config.key_testbed_name.value]
     start_time = logger.get_log_file_timestamp()
     self.id = "{}@{}".format(self.testbed_name, start_time)
     # log_path should be set before parsing configs.
     l_path = os.path.join(
         self.test_configs[keys.Config.key_log_path.value],
         self.testbed_name, start_time)
     self.log_path = os.path.abspath(l_path)
     logger.setup_test_logger(self.log_path, self.testbed_name)
     self.log = logging.getLogger()
     self.controller_registry = {}
     self.controller_destructors = {}
     self.run_list = run_list
     self.results = records.TestResult()
     self.running = False
예제 #7
0
        def generate_test_run_log_path(self):
            """Geneartes the log path for a test run.

      The log path includes a timestamp that is set in this call.

      There is usually a minor difference between this timestamp and the actual
      starting point of the test run. This is because the log path must be set
      up *before* the test run actually starts, so all information of a test
      run can be properly captured.

      The generated value can be accessed via `self.root_output_path`.

      Returns:
        String, the generated log path.
      """
            self._logger_start_time = logger.get_log_file_timestamp()
            self.root_output_path = os.path.join(self._log_dir,
                                                 self._testbed_name,
                                                 self._logger_start_time)
            return self.root_output_path
예제 #8
0
  def generate_filename(self,
                        file_type,
                        time_identifier=None,
                        extension_name=None):
    """Generates a name for an output file related to this device.

    The name follows the pattern:

      {file type},{debug_tag},{serial},{model},{time identifier}.{ext}

    "debug_tag" is only added if it's different from the serial. "ext" is
    added if specified by user.

    Args:
      file_type: string, type of this file, like "logcat" etc.
      time_identifier: string or RuntimeTestInfo. If a `RuntimeTestInfo`
        is passed in, the `signature` of the test case will be used. If
        a string is passed in, the string itself will be used.
        Otherwise the current timestamp will be used.
      extension_name: string, the extension name of the file.

    Returns:
      String, the filename generated.
    """
    time_str = time_identifier
    if time_identifier is None:
      time_str = mobly_logger.get_log_file_timestamp()
    elif isinstance(time_identifier, runtime_test_info.RuntimeTestInfo):
      time_str = time_identifier.signature
    filename_tokens = [file_type]
    if self.debug_tag != self.serial:
      filename_tokens.append(self.debug_tag)
    filename_tokens.extend([self.serial, self.model, time_str])
    filename_str = ','.join(filename_tokens)
    if extension_name is not None:
      filename_str = '%s.%s' % (filename_str, extension_name)
    filename_str = mobly_logger.sanitize_filename(filename_str)
    self.log.debug('Generated filename: %s', filename_str)
    return filename_str
예제 #9
0
    def setup_logger(self):
        """Sets up logging for the next test run.

        This is called automatically in 'run', so normally, this method doesn't
        need to be called. Only use this method if you want to use Mobly's
        logger before the test run starts.

        .. code-block:: python

            tr = TestRunner(...)
            tr.setup_logger()
            logging.info(...)
            tr.run()

        """
        if self._log_path is not None:
            return

        self._start_time = logger.get_log_file_timestamp()
        self._log_path = os.path.join(self._log_dir, self._test_bed_name,
                                      self._start_time)
        logger.setup_test_logger(self._log_path, self._test_bed_name)
예제 #10
0
 def _update_log_path(self):
     """Updates the logging values with the current timestamp."""
     self._start_time = logger.get_log_file_timestamp()
     self._log_path = os.path.join(self._log_dir, self._test_bed_name,
                                   self._start_time)