Example #1
0
    def create_output_excerpts(self, test_info):
        """Convenient method for creating excerpts of adb logcat.

        This moves the current content of `self.adb_logcat_file_path` to the
        log directory specific to the current test.

        Call this method at the end of: `setup_class`, `teardown_test`, and
        `teardown_class`.

        Args:
            test_info: `self.current_test_info` in a Mobly test.

        Returns:
            List of strings, the absolute paths to excerpt files.
        """
        self.pause()
        dest_path = test_info.output_path
        utils.create_dir(dest_path)
        filename = self._ad.generate_filename(self.OUTPUT_FILE_TYPE, test_info,
                                              'txt')
        excerpt_file_path = os.path.join(dest_path, filename)
        shutil.move(self.adb_logcat_file_path, excerpt_file_path)
        self._ad.log.debug('logcat excerpt created at: %s', excerpt_file_path)
        self.resume()
        return [excerpt_file_path]
Example #2
0
 def test_cat_adb_log_with_unicode(self, mock_timestamp_getter,
                                   stop_proc_mock, start_proc_mock,
                                   FastbootProxy, MockAdbProxy):
     """Verifies that AndroidDevice.cat_adb_log loads the correct adb log
     file, locates the correct adb log lines within the given time range,
     and writes the lines to the correct output file.
     """
     mock_serial = '1'
     ad = android_device.AndroidDevice(serial=mock_serial)
     logcat_service = logcat.Logcat(ad)
     logcat_service._enable_logpersist()
     # Direct the log path of the ad to a temp dir to avoid racing.
     logcat_service._ad._log_path = self.tmp_dir
     # Expect error if attempted to cat adb log before starting adb logcat.
     expected_msg = ('.* Attempting to cat adb log when none'
                     ' has been collected.')
     with self.assertRaisesRegex(logcat.Error, expected_msg):
         logcat_service.cat_adb_log('some_test', MOCK_ADB_LOGCAT_BEGIN_TIME)
     logcat_service.start()
     utils.create_dir(ad.log_path)
     mock_adb_log_path = logcat_service.adb_logcat_file_path
     with io.open(mock_adb_log_path, 'w', encoding='utf-8') as f:
         f.write(MOCK_ADB_UNICODE_LOGCAT)
     cat_file_path = logcat_service.cat_adb_log('some_test',
                                                MOCK_ADB_LOGCAT_BEGIN_TIME)
     with io.open(cat_file_path, 'r', encoding='utf-8') as f:
         actual_cat = f.read()
     self.assertEqual(actual_cat,
                      ''.join(MOCK_ADB_UNICODE_LOGCAT_CAT_RESULT))
     # Stops adb logcat.
     logcat_service.stop()
Example #3
0
 def start_adb_logcat(self):
     """Starts a standing adb logcat collection in separate subprocesses and
     save the logcat in a file.
     """
     if self._adb_logcat_process:
         raise DeviceError(
             self,
             'Logcat thread is already running, cannot start another one.')
     # Disable adb log spam filter for rootable. Have to stop and clear
     # settings first because 'start' doesn't support --clear option before
     # Android N.
     if self.is_rootable:
         self.adb.shell('logpersist.stop --clear')
         self.adb.shell('logpersist.start')
     f_name = 'adblog,%s,%s.txt' % (self.model, self.serial)
     utils.create_dir(self.log_path)
     logcat_file_path = os.path.join(self.log_path, f_name)
     try:
         extra_params = self.adb_logcat_param
     except AttributeError:
         extra_params = '-b all'
     cmd = 'adb -s %s logcat -v threadtime %s >> %s' % (
         self.serial, extra_params, logcat_file_path)
     self._adb_logcat_process = utils.start_standing_subprocess(cmd)
     self.adb_logcat_file_path = logcat_file_path
Example #4
0
 def test_AndroidDevice_cat_adb_log_with_unicode(
         self, mock_timestamp_getter, stop_proc_mock, start_proc_mock,
         FastbootProxy, MockAdbProxy):
     """Verifies that AndroidDevice.cat_adb_log loads the correct adb log
     file, locates the correct adb log lines within the given time range,
     and writes the lines to the correct output file.
     """
     mock_serial = '1'
     ad = android_device.AndroidDevice(serial=mock_serial)
     # Direct the log path of the ad to a temp dir to avoid racing.
     ad._log_path_base = self.tmp_dir
     # Expect error if attempted to cat adb log before starting adb logcat.
     expected_msg = ('.* Attempting to cat adb log when none'
                     ' has been collected.')
     with self.assertRaisesRegex(android_device.Error, expected_msg):
         ad.cat_adb_log('some_test', MOCK_ADB_LOGCAT_BEGIN_TIME)
     ad.start_adb_logcat()
     utils.create_dir(ad.log_path)
     mock_adb_log_path = os.path.join(ad.log_path, 'adblog,%s,%s.txt' %
                                      (ad.model, ad.serial))
     with io.open(mock_adb_log_path, 'w', encoding='utf-8') as f:
         f.write(MOCK_ADB_UNICODE_LOGCAT)
     ad.cat_adb_log('some_test', MOCK_ADB_LOGCAT_BEGIN_TIME)
     cat_file_path = os.path.join(
         ad.log_path, 'AdbLogExcerpts',
         ('some_test,02-29 14-02-20.123,%s,%s.txt') % (ad.model, ad.serial))
     with io.open(cat_file_path, 'r', encoding='utf-8') as f:
         actual_cat = f.read()
     self.assertEqual(actual_cat,
                      ''.join(MOCK_ADB_UNICODE_LOGCAT_CAT_RESULT))
     # Stops adb logcat.
     ad.stop_adb_logcat()
Example #5
0
    def start_adb_logcat(self, clear_log=True):
        """Starts a standing adb logcat collection in separate subprocesses and
        save the logcat in a file.

        This clears the previous cached logcat content on device.

        Args:
            clear: If True, clear device log before starting logcat.
        """
        if self._adb_logcat_process:
            raise DeviceError(
                self,
                'Logcat thread is already running, cannot start another one.')
        if clear_log:
            self._clear_adb_log()
        # Disable adb log spam filter for rootable devices. Have to stop and
        # clear settings first because 'start' doesn't support --clear option
        # before Android N.
        if self.is_rootable:
            self.adb.shell('logpersist.stop --clear')
            self.adb.shell('logpersist.start')
        f_name = 'adblog,%s,%s.txt' % (self.model, self.serial)
        utils.create_dir(self.log_path)
        logcat_file_path = os.path.join(self.log_path, f_name)
        try:
            extra_params = self.adb_logcat_param
        except AttributeError:
            extra_params = ''
        cmd = '"%s" -s %s logcat -v threadtime %s >> "%s"' % (adb.ADB,
                                                              self.serial,
                                                              extra_params,
                                                              logcat_file_path)
        process = utils.start_standing_subprocess(cmd, shell=True)
        self._adb_logcat_process = process
        self.adb_logcat_file_path = logcat_file_path
Example #6
0
    def __init__(self, configs):
        """Constructor of BaseTestClass.

    The constructor takes a config_parser.TestRunConfig object and which has
    all the information needed to execute this test class, like log_path
    and controller configurations. For details, see the definition of class
    config_parser.TestRunConfig.

    Args:
      configs: A config_parser.TestRunConfig object.
    """
        self.tests = []
        class_identifier = self.__class__.__name__
        if configs.test_class_name_suffix:
            class_identifier = '%s_%s' % (class_identifier,
                                          configs.test_class_name_suffix)
        if self.TAG is None:
            self.TAG = class_identifier
        # Set params.
        self.root_output_path = configs.log_path
        self.log_path = os.path.join(self.root_output_path, class_identifier)
        utils.create_dir(self.log_path)
        # Deprecated, use 'testbed_name'
        self.test_bed_name = configs.test_bed_name
        self.testbed_name = configs.testbed_name
        self.user_params = configs.user_params
        self.results = records.TestResult()
        self.summary_writer = configs.summary_writer
        self._generated_test_table = collections.OrderedDict()
        self._controller_manager = controller_manager.ControllerManager(
            class_name=self.TAG, controller_configs=configs.controller_configs)
        self.controller_configs = self._controller_manager.controller_configs
Example #7
0
    def start_adb_logcat(self, clear_log=True):
        """Starts a standing adb logcat collection in separate subprocesses and
        save the logcat in a file.

        This clears the previous cached logcat content on device.

        Args:
            clear: If True, clear device log before starting logcat.
        """
        if self._adb_logcat_process:
            raise DeviceError(
                self,
                'Logcat thread is already running, cannot start another one.')
        if clear_log:
            self._clear_adb_log()

        self._enable_logpersist()

        f_name = 'adblog,%s,%s.txt' % (self.model, self._normalized_serial)
        utils.create_dir(self.log_path)
        logcat_file_path = os.path.join(self.log_path, f_name)
        try:
            extra_params = self.adb_logcat_param
        except AttributeError:
            extra_params = ''
        cmd = '"%s" -s %s logcat -v threadtime %s >> "%s"' % (
            adb.ADB, self.serial, extra_params, logcat_file_path)
        process = utils.start_standing_subprocess(cmd, shell=True)
        self._adb_logcat_process = process
        self.adb_logcat_file_path = logcat_file_path
Example #8
0
    def create_output_excerpts(self, test_info):
        """Convenient method for creating excerpts of adb logcat.

        This copies logcat lines from self.adb_logcat_file_path to an excerpt
        file, starting from the location where the previous excerpt ended.

        Call this method at the end of: `setup_class`, `teardown_test`, and
        `teardown_class`.

        Args:
            test_info: `self.current_test_info` in a Mobly test.

        Returns:
            List of strings, the absolute paths to excerpt files.
        """
        dest_path = test_info.output_path
        utils.create_dir(dest_path)
        filename = self._ad.generate_filename(self.OUTPUT_FILE_TYPE, test_info,
                                              'txt')
        excerpt_file_path = os.path.join(dest_path, filename)
        with io.open(excerpt_file_path, 'w', encoding='utf-8',
                     errors='replace') as out:
            while True:
                line = self._adb_logcat_file_obj.readline()
                if not line:
                    break
                out.write(line)
        self._ad.log.debug('logcat excerpt created at: %s', excerpt_file_path)
        return [excerpt_file_path]
Example #9
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
Example #10
0
def setup_test_logger(log_path, prefix=None, alias='latest'):
    """Customizes the root logger for a test run.

  In addition to configuring the Mobly logging handlers, this also sets two
  attributes on the `logging` module for the output directories:

  root_output_path: path to the directory for the entire test run.
  log_path: same as `root_output_path` outside of a test class run. In the
    context of a test class run, this is the output directory for files
    specific to a test class.

  Args:
    log_path: string, the location of the report file.
    prefix: optional string, a prefix for each log line in terminal.
    alias: optional string, The name of the alias to use for the latest log
      directory. If a falsy value is provided, then the alias directory
      will not be created, which is useful to save storage space when the
      storage system (e.g. ZIP files) does not properly support
      shortcut/symlinks.
  """
    utils.create_dir(log_path)
    _setup_test_logger(log_path, prefix)
    logging.info('Test output folder: "%s"', log_path)
    if alias:
        create_latest_log_alias(log_path, alias=alias)
Example #11
0
    def run(self):
        """Executes tests.

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

    This meethod should usually be called within the runner's `mobly_logger`
    context. If you must use this method outside of the context, you should
    make sure `self._test_run_metadata.generate_test_run_log_path` is called
    before each invocation of `run`.

    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.')

        # Officially starts the test run.
        self._test_run_metadata.set_start_point()

        # Ensure the log path exists. Necessary if `run` is used outside of the
        # `mobly_logger` context.
        utils.create_dir(self._test_run_metadata.root_output_path)

        summary_writer = records.TestSummaryWriter(
            os.path.join(self._test_run_metadata.root_output_path,
                         records.OUTPUT_FILE_SUMMARY))
        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 = self._test_run_metadata.root_output_path
                test_config.summary_writer = summary_writer
                test_config.test_class_name_suffix = test_run_info.test_class_name_suffix
                try:
                    self._run_test_class(config=test_config,
                                         test_class=test_run_info.test_class,
                                         tests=test_run_info.tests)
                except signals.TestAbortAll as e:
                    logging.warning(
                        'Abort all subsequent test classes. Reason: %s', e)
                    raise
        finally:
            summary_writer.dump(self.results.summary_dict(),
                                records.TestSummaryEntryType.SUMMARY)
            self._test_run_metadata.set_end_point()
            # Show the test run summary.
            summary_lines = [
                f'Summary for test run {self._test_run_metadata.run_id}:',
                f'Total time elapsed {self._test_run_metadata.time_elapsed_sec}s',
                f'Artifacts are saved in "{self._test_run_metadata.root_output_path}"',
                f'Test results: {self.results.summary_str()}'
            ]
            logging.info('\n'.join(summary_lines))
Example #12
0
    def take_bug_report(self,
                        test_name,
                        begin_time,
                        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.
            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.
        """
        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:
            br_path = utils.abs_path(destination)
        else:
            br_path = os.path.join(self.log_path, 'BugReports')
        utils.create_dir(br_path)
        base_name = ',%s,%s.txt' % (begin_time, self._normalized_serial)
        if new_br:
            base_name = base_name.replace('.txt', '.zip')
        test_name_len = utils.MAX_FILENAME_LEN - len(base_name)
        out_name = test_name[:test_name_len] + base_name
        full_out_path = os.path.join(br_path, out_name.replace(' ', r'\ '))
        # in case device restarted, wait for adb interface to return
        self.wait_for_boot_completion()
        self.log.info('Taking bugreport for %s.', test_name)
        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.info('Bugreport for %s taken at %s.', test_name,
                      full_out_path)
Example #13
0
    def cat_adb_log(self, tag, begin_time):
        """Takes an excerpt of the adb logcat log from a certain time point to
        current time.

        .. deprecated:: 1.10
            Use :func:`create_output_excerpts` instead.

        Args:
            tag: An identifier of the time period, usualy the name of a test.
            begin_time: Logline format timestamp of the beginning of the time
                period.

        Returns:
            String, full path to the excerpt file created.
        """
        if not self.adb_logcat_file_path:
            raise Error(
                self._ad,
                'Attempting to cat adb log when none has been collected.')
        end_time = mobly_logger.get_log_line_timestamp()
        self._ad.log.debug('Extracting adb log from logcat.')
        adb_excerpt_path = os.path.join(self._ad.log_path, 'AdbLogExcerpts')
        utils.create_dir(adb_excerpt_path)
        out_name = '%s,%s.txt' % (tag, begin_time)
        out_name = mobly_logger.sanitize_filename(out_name)
        full_adblog_path = os.path.join(adb_excerpt_path, out_name)
        with io.open(full_adblog_path, 'w', encoding='utf-8') as out:
            in_file = self.adb_logcat_file_path
            with io.open(in_file, 'r', encoding='utf-8',
                         errors='replace') as f:
                in_range = False
                while True:
                    line = None
                    try:
                        line = f.readline()
                        if not line:
                            break
                    except:
                        continue
                    line_time = line[:mobly_logger.log_line_timestamp_len]
                    if not mobly_logger.is_valid_logline_timestamp(line_time):
                        continue
                    if self._is_timestamp_in_range(line_time, begin_time,
                                                   end_time):
                        in_range = True
                        if not line.endswith('\n'):
                            line += '\n'
                        out.write(line)
                    else:
                        if in_range:
                            break
        return full_adblog_path
Example #14
0
def setup_test_logger(log_path, prefix=None, filename=None):
    """Customizes the root logger for a test run.

    Args:
        log_path: Location of the report file.
        prefix: A prefix for each log line in terminal.
        filename: Name of the files. The default is the time the objects
            are requested.
    """
    utils.create_dir(log_path)
    _setup_test_logger(log_path, prefix)
    logging.info('Test output folder: "%s"', log_path)
    create_latest_log_alias(log_path)
Example #15
0
def _setup_test_logger(log_path, prefix=None, filename=None):
    """Customizes the root logger for a test run.

    The logger object has a stream handler and a file handler. The stream
    handler logs INFO level to the terminal, the file handler logs DEBUG
    level to files.

    Args:
        log_path: Location of the log file.
        prefix: A prefix for each log line in terminal.
        filename: Name of the log file. The default is the time the logger
            is requested.
    """
    log = logging.getLogger()
    kill_test_logger(log)
    log.propagate = False
    log.setLevel(logging.DEBUG)
    # Log info to stream
    terminal_format = log_line_format
    if prefix:
        terminal_format = '[%s] %s' % (prefix, log_line_format)
    c_formatter = logging.Formatter(terminal_format, log_line_time_format)
    ch = logging.StreamHandler(sys.stdout)
    ch.setFormatter(c_formatter)
    ch.setLevel(logging.INFO)
    # Log everything to file
    f_formatter = logging.Formatter(log_line_format, log_line_time_format)
    # All the logs of this test class go into one directory
    if filename is None:
        filename = get_log_file_timestamp()
        utils.create_dir(log_path)
    # TODO(#270): Deprecate `test_run_details.txt` when we remove old output
    # format support.
    fh = logging.FileHandler(os.path.join(log_path, 'test_run_details.txt'))
    fh.setFormatter(f_formatter)
    fh.setLevel(logging.DEBUG)
    log.addHandler(fh)
    # Write logger output to files
    fh_info = logging.FileHandler(
        os.path.join(log_path, records.OUTPUT_FILE_INFO_LOG))
    fh_info.setFormatter(f_formatter)
    fh_info.setLevel(logging.INFO)
    fh_debug = logging.FileHandler(
        os.path.join(log_path, records.OUTPUT_FILE_DEBUG_LOG))
    fh_debug.setFormatter(f_formatter)
    fh_debug.setLevel(logging.DEBUG)
    log.addHandler(ch)
    log.addHandler(fh_info)
    log.addHandler(fh_debug)
    log.log_path = log_path
    logging.log_path = log_path
Example #16
0
def setup_test_logger(log_path, prefix=None, filename=None):
    """Customizes the root logger for a test run.

    Args:
        log_path: Location of the report file.
        prefix: A prefix for each log line in terminal.
        filename: Name of the files. The default is the time the objects
            are requested.
    """
    if filename is None:
        filename = get_log_file_timestamp()
    create_dir(log_path)
    logger = _setup_test_logger(log_path, prefix, filename)
    create_latest_log_alias(log_path)
Example #17
0
    def cat_adb_log(self, tag, begin_time):
        """Takes an excerpt of the adb logcat log from a certain time point to
        current time.

        Args:
            tag: An identifier of the time period, usualy the name of a test.
            begin_time: Logline format timestamp of the beginning of the time
                period.
        """
        if not self.adb_logcat_file_path:
            raise Error(
                self._ad,
                'Attempting to cat adb log when none has been collected.')
        end_time = mobly_logger.get_log_line_timestamp()
        self._ad.log.debug('Extracting adb log from logcat.')
        adb_excerpt_path = os.path.join(self._ad.log_path, 'AdbLogExcerpts')
        utils.create_dir(adb_excerpt_path)
        f_name = os.path.basename(self.adb_logcat_file_path)
        out_name = f_name.replace('adblog,', '').replace('.txt', '')
        out_name = ',%s,%s.txt' % (begin_time, out_name)
        out_name = out_name.replace(':', '-')
        tag_len = utils.MAX_FILENAME_LEN - len(out_name)
        tag = tag[:tag_len]
        out_name = tag + out_name
        full_adblog_path = os.path.join(adb_excerpt_path, out_name)
        with io.open(full_adblog_path, 'w', encoding='utf-8') as out:
            in_file = self.adb_logcat_file_path
            with io.open(in_file, 'r', encoding='utf-8',
                         errors='replace') as f:
                in_range = False
                while True:
                    line = None
                    try:
                        line = f.readline()
                        if not line:
                            break
                    except:
                        continue
                    line_time = line[:mobly_logger.log_line_timestamp_len]
                    if not mobly_logger.is_valid_logline_timestamp(line_time):
                        continue
                    if self._is_timestamp_in_range(line_time, begin_time,
                                                   end_time):
                        in_range = True
                        if not line.endswith('\n'):
                            line += '\n'
                        out.write(line)
                    else:
                        if in_range:
                            break
Example #18
0
 def _start(self):
     """The actual logic of starting logcat."""
     self._enable_logpersist()
     logcat_file_path = self._config.output_file_path
     if not logcat_file_path:
         f_name = self._ad.generate_filename(self.OUTPUT_FILE_TYPE,
                                             extension_name='txt')
         logcat_file_path = os.path.join(self._ad.log_path, f_name)
     utils.create_dir(os.path.dirname(logcat_file_path))
     cmd = '"%s" -s %s logcat -v threadtime %s >> "%s"' % (
         adb.ADB, self._ad.serial, self._config.logcat_params,
         logcat_file_path)
     process = utils.start_standing_subprocess(cmd, shell=True)
     self._adb_logcat_process = process
     self.adb_logcat_file_path = logcat_file_path
Example #19
0
 def _start(self):
     """The actual logic of starting logcat."""
     self._enable_logpersist()
     logcat_file_path = self._configs.output_file_path
     if not logcat_file_path:
         f_name = 'adblog,%s,%s.txt' % (self._ad.model,
                                        self._ad._normalized_serial)
         logcat_file_path = os.path.join(self._ad.log_path, f_name)
     utils.create_dir(os.path.dirname(logcat_file_path))
     cmd = '"%s" -s %s logcat -v threadtime %s >> "%s"' % (
         adb.ADB, self._ad.serial, self._configs.logcat_params,
         logcat_file_path)
     process = utils.start_standing_subprocess(cmd, shell=True)
     self._adb_logcat_process = process
     self.adb_logcat_file_path = logcat_file_path
Example #20
0
    def save_to_text_file(monsoon_data, file_path):
        """Save multiple MonsoonData objects to a text file.

        Args:
            monsoon_data: A list of MonsoonData objects to write to a text
                file.
            file_path: The full path of the file to save to, including the file
                name.
        """
        if not monsoon_data:
            raise MonsoonError("Attempting to write empty Monsoon data to "
                               "file, abort")
        utils.create_dir(os.path.dirname(file_path))
        with io.open(file_path, 'w', encoding='utf-8') as f:
            for md in monsoon_data:
                f.write(str(md))
                f.write(MonsoonData.delimiter)
Example #21
0
def setup_test_logger(log_path, prefix=None, alias='latest'):
    """Customizes the root logger for a test run.

    Args:
        log_path: string, the location of the report file.
        prefix: optional string, a prefix for each log line in terminal.
        alias: optional string, The name of the alias to use for the latest log
            directory. If a falsy value is provided, then the alias directory
            will not be created, which is useful to save storage space when the
            storage system (e.g. ZIP files) does not properly support
            shortcut/symlinks.
    """
    utils.create_dir(log_path)
    _setup_test_logger(log_path, prefix)
    logging.info('Test output folder: "%s"', log_path)
    if alias:
        create_latest_log_alias(log_path, alias=alias)
Example #22
0
    def create_per_test_excerpt(self, current_test_info):
        """Convenient method for creating excerpts of adb logcat.

        To use this feature, call this method at the end of: `setup_class`,
        `teardown_test`, and `teardown_class`.

        This moves the current content of `self.adb_logcat_file_path` to the
        log directory specific to the current test.

        Args:
          current_test_info: `self.current_test_info` in a Mobly test.
        """
        self.pause()
        dest_path = current_test_info.output_path
        utils.create_dir(dest_path)
        self._ad.log.debug('AdbLog exceprt location: %s', dest_path)
        shutil.move(self.adb_logcat_file_path, dest_path)
        self.resume()
Example #23
0
    def take_screenshot(self, destination):
        """Takes a screenshot of the device.

        Args:
            destination: string, full path to the directory to save in.

        Returns:
            string, full path to the screenshot file on the host.
        """
        filename = self.generate_filename('screenshot', extension_name='png')
        device_path = os.path.join('/storage/emulated/0/', filename)
        self.adb.shell(['screencap', '-p', device_path],
                       timeout=TAKE_SCREENSHOT_TIMEOUT_SECOND)
        utils.create_dir(destination)
        self.adb.pull([device_path, destination])
        pic_path = os.path.join(destination, filename)
        self.log.debug('Screenshot taken, saved on the host: %s', pic_path)
        self.adb.shell(['rm', device_path])
        return pic_path
Example #24
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.')

        # Ensure the log path exists. Necessary if `run` is used outside of the
        # `mobly_logger` context.
        utils.create_dir(self._log_path)

        summary_writer = records.TestSummaryWriter(
            os.path.join(self._log_path, records.OUTPUT_FILE_SUMMARY))
        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 = self._log_path
                test_config.summary_writer = summary_writer
                test_config.test_class_name_suffix = test_run_info.test_class_name_suffix
                try:
                    self._run_test_class(config=test_config,
                                         test_class=test_run_info.test_class,
                                         tests=test_run_info.tests)
                except signals.TestAbortAll as e:
                    logging.warning(
                        'Abort all subsequent test classes. Reason: %s', e)
                    raise
        finally:
            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, self._start_time,
                self.results.summary_str())
            logging.info(msg.strip())
Example #25
0
 def _start(self):
     """The actual logic of starting logcat."""
     self._enable_logpersist()
     if self._config.output_file_path:
         self._close_logcat_file()
         self.adb_logcat_file_path = self._config.output_file_path
     if not self.adb_logcat_file_path:
         f_name = self._ad.generate_filename(self.OUTPUT_FILE_TYPE,
                                             extension_name='txt')
         logcat_file_path = os.path.join(self._ad.log_path, f_name)
         self.adb_logcat_file_path = logcat_file_path
     utils.create_dir(os.path.dirname(self.adb_logcat_file_path))
     # In debugging mode of IntelijIDEA, "patch_args" remove
     # double quotes in args if starting and ending with it.
     # Add spaces at beginning and at last to fix this issue.
     cmd = ' "%s" -s %s logcat -v threadtime -T 1 %s >> "%s" ' % (
         adb.ADB, self._ad.serial, self._config.logcat_params,
         self.adb_logcat_file_path)
     process = utils.start_standing_subprocess(cmd, shell=True)
     self._adb_logcat_process = process
Example #26
0
    def start(self, extra_args="", tag=""):
        """Starts iperf server on specified port.

        Args:
            extra_args: A string representing extra arguments to start iperf
                server with.
            tag: Appended to log file name to identify logs from different
                iperf runs.
        """
        if self.started:
            return
        utils.create_dir(self.log_path)
        if tag:
            tag = tag + ','
        out_file_name = "IPerfServer,{},{}{}.log".format(
            self.port, tag, len(self.log_files))
        full_out_path = os.path.join(self.log_path, out_file_name)
        cmd = '%s %s > %s' % (self.iperf_str, extra_args, full_out_path)
        self.iperf_process = utils.start_standing_subprocess(cmd, shell=True)
        self.log_files.append(full_out_path)
        self.started = True
Example #27
0
def _setup_test_logger(log_path, prefix=None, filename=None):
    """Customizes the root logger for a test run.

    The logger object has a stream handler and a file handler. The stream
    handler logs INFO level to the terminal, the file handler logs DEBUG
    level to files.

    Args:
        log_path: Location of the log file.
        prefix: A prefix for each log line in terminal.
        filename: Name of the log file. The default is the time the logger
                  is requested.
    """
    log = logging.getLogger()
    kill_test_logger(log)
    log.propagate = False
    log.setLevel(logging.DEBUG)
    # Log info to stream
    terminal_format = log_line_format
    if prefix:
        terminal_format = "[{}] {}".format(prefix, log_line_format)
    c_formatter = logging.Formatter(terminal_format, log_line_time_format)
    ch = logging.StreamHandler(sys.stdout)
    ch.setFormatter(c_formatter)
    ch.setLevel(logging.INFO)
    # Log everything to file
    f_formatter = logging.Formatter(log_line_format, log_line_time_format)
    # All the logs of this test class go into one directory
    if filename is None:
        filename = get_log_file_timestamp()
        create_dir(log_path)
    fh = logging.FileHandler(os.path.join(log_path, 'test_run_details.txt'))
    fh.setFormatter(f_formatter)
    fh.setLevel(logging.DEBUG)
    log.addHandler(ch)
    log.addHandler(fh)
    log.log_path = log_path
    logging.log_path = log_path
Example #28
0
    def take_bug_report(self, test_name, begin_time):
        """Takes a bug report on the device and stores it in a file.

        Args:
            test_name: Name of the test case that triggered this bug report.
            begin_time: Logline format timestamp taken when the test started.
        """
        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
        br_path = os.path.join(self.log_path, "BugReports")
        utils.create_dir(br_path)
        base_name = ",{},{}.txt".format(begin_time, self.serial)
        if new_br:
            base_name = base_name.replace(".txt", ".zip")
        test_name_len = utils.MAX_FILENAME_LEN - len(base_name)
        out_name = test_name[:test_name_len] + base_name
        full_out_path = os.path.join(br_path, out_name.replace(' ', '\ '))
        # in case device restarted, wait for adb interface to return
        self.wait_for_boot_completion()
        self.log.info("Taking bugreport for %s.", test_name)
        if new_br:
            out = self.adb.shell("bugreportz").decode("utf-8")
            if not out.startswith("OK"):
                raise Error("Failed to take bugreport on %s: %s" %
                            (self.serial, out))
            br_out_path = out.split(':')[1].strip()
            self.adb.pull("%s %s" % (br_out_path, full_out_path))
        else:
            self.adb.bugreport(" > {}".format(full_out_path))
        self.log.info("Bugreport for %s taken at %s.", test_name,
                      full_out_path)
Example #29
0
 def start_adb_logcat(self):
     """Starts a standing adb logcat collection in separate subprocesses and
     save the logcat in a file.
     """
     if self.is_adb_logcat_on:
         raise Error(("Android device {} already has an adb "
                      "logcat thread going on. Cannot start "
                      "another one.").format(self.serial))
     # Disable adb log spam filter. Have to stop and clear settings first
     # because 'start' doesn't support --clear option before Android N.
     self.adb.shell("logpersist.stop --clear")
     self.adb.shell("logpersist.start")
     f_name = "adblog,{},{}.txt".format(self.model, self.serial)
     utils.create_dir(self.log_path)
     logcat_file_path = os.path.join(self.log_path, f_name)
     try:
         extra_params = self.adb_logcat_param
     except AttributeError:
         extra_params = "-b all"
     cmd = "adb -s {} logcat -v threadtime {} >> {}".format(
         self.serial, extra_params, logcat_file_path)
     self.adb_logcat_process = utils.start_standing_subprocess(cmd)
     self.adb_logcat_file_path = logcat_file_path
Example #30
0
    def take_bug_report(self, test_name, begin_time):
        """Takes a bug report on the device and stores it in a file.

        Args:
            test_name: Name of the test case that triggered this bug report.
            begin_time: Logline format timestamp taken when the test started.
        """
        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
        br_path = os.path.join(self.log_path, 'BugReports')
        utils.create_dir(br_path)
        base_name = ',%s,%s.txt' % (begin_time, self.serial)
        if new_br:
            base_name = base_name.replace('.txt', '.zip')
        test_name_len = utils.MAX_FILENAME_LEN - len(base_name)
        out_name = test_name[:test_name_len] + base_name
        full_out_path = os.path.join(br_path, out_name.replace(' ', r'\ '))
        # in case device restarted, wait for adb interface to return
        self.wait_for_boot_completion()
        self.log.info('Taking bugreport for %s.', test_name)
        if new_br:
            out = self.adb.shell('bugreportz').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('%s %s' % (br_out_path, full_out_path))
        else:
            self.adb.bugreport(' > %s' % full_out_path)
        self.log.info('Bugreport for %s taken at %s.', test_name,
                      full_out_path)