Beispiel #1
0
    def run_once(self):
        if os.geteuid() != 0:
            raise error.TestNAError('This test needs to be run under root')

        for path in [self._CGPT_PATH, self._ROOTDEV_PATH]:
            if not os.path.isfile(path):
                raise error.TestNAError('%s not found' % path)

        root_device = site_utils.get_root_device()
        if not root_device:
            raise error.TestNAError('Could not find the root device')
        logging.debug('Root device: %s' % root_device)

        root_partitions = self.get_root_partitions(root_device)
        if not root_partitions:
            raise error.TestNAError('Could not find any root partition')
        logging.debug('Root partitions: %s' % ', '.join(root_partitions))

        processes = self.get_process_list([self._UPDATE_ENGINE_PATH])
        if not processes:
            raise error.TestNAError('Could not find any process')
        logging.debug('Active processes: %s' % ', '.join(processes))

        for process in processes:
            process_exe = self.get_process_executable(process)
            mounts_file = '/proc/%s/mounts' % process
            mounted_devices = self.get_mounted_devices(mounts_file)
            for partition in root_partitions:
                if partition in mounted_devices:
                    raise error.TestFail(
                        'Root partition "%s" is mounted by process %s (%s)' %
                        (partition, process, process_exe))
    def run_once(self, check_link_speed=()):
        # Use rootdev to find the underlying block device even if the
        # system booted to /dev/dm-0.
        device = site_utils.get_root_device()

        # Check the device is fixed

        def IsFixed(dev):
            sysfs_path = '/sys/block/%s/removable' % dev
            return (os.path.exists(sysfs_path)
                    and open(sysfs_path).read().strip() == '0')

        alpha_re = re.compile(r'^/dev/([a-zA-Z]+)$')
        alnum_re = re.compile(r'^/dev/([a-zA-Z]+[0-9]+)$')
        dev = alpha_re.findall(device) + alnum_re.findall(device)
        if len(dev) != 1 or not IsFixed(dev[0]):
            raise error.TestFail('The main disk %s is not fixed' % dev)

        # If it is an mmcblk device, then it is SSD.
        # Else run hdparm to check for SSD.

        if re.search("mmcblk", device):
            return

        hdparm = utils.run('/sbin/hdparm -I %s' % device)

        # Check if device is a SSD
        match = re.search(r'Nominal Media Rotation Rate: (.+)$', hdparm.stdout,
                          re.MULTILINE)
        if match and match.group(1):
            if match.group(1) != 'Solid State Device':
                if utils.get_board() in self.boards_with_hdd:
                    return
                raise error.TestFail('The main disk is not a SSD, '
                                     'Rotation Rate: %s' % match.group(1))
        else:
            raise error.TestFail('Rotation Rate not reported from the device, '
                                 'unable to ensure it is a SSD')

        # Check if SSD is > 8GB in size
        match = re.search("device size with M = 1000\*1000: (.+) MBytes",
                          hdparm.stdout, re.MULTILINE)
        if match and match.group(1):
            size = int(match.group(1))
            self.write_perf_keyval({"mb_ssd_device_size": size})
        else:
            raise error.TestFail('Device size info missing from the device')

        # Check supported link speed.
        #
        # check_link_speed is an empty tuple by default, which does not perform
        # link speed checking.  You can run the test while specifying
        # check_link_speed=('1.5Gb/s', '3.0Gb/s') to check the 2 signaling
        # speeds are both supported.
        for link_speed in check_link_speed:
            if not re.search(r'Gen. signaling speed \(%s\)' % link_speed,
                             hdparm.stdout, re.MULTILINE):
                raise error.TestFail('Link speed %s not supported' %
                                     link_speed)
Beispiel #3
0
    def run_once(self, dev='/dev/sda'):
        """
        Measure write performance before and after trim.

        This test use an entire disk so we need to boot from usb.

        @param dev: block device to test
        """
        logging.info('Target device: %s', dev)

        # Check that device exist.
        if not os.path.exists(dev):
            msg = 'Test failed with error: %s not exist' % dev
            raise error.TestFail(msg)

        # Check that device is not rootdev.
        rootdev = site_utils.get_root_device()
        if dev == rootdev:
            raise error.TestFail('Can not test on root device')

        # Use fio to fill device first.
        self.job.run_test('hardware_StorageFio',
                          disable_sysinfo=True,
                          dev=dev,
                          filesize=0,
                          requirements=[('disk_fill', [])],
                          tag='disk_fill')

        # Use 4k random write with queue depth = 32 because manufacture usually
        # uses this use case in the SSD specification.
        # Also, print result every minute to look at the performance drop trend
        # over time. Result reported by autotest will be the last minute one.
        requirements = [('4k_write_qd32', ['--status-interval=60'])]

        # Check write performance
        self.job.run_test('hardware_StorageFio',
                          disable_sysinfo=True,
                          dev=dev,
                          filesize=0,
                          requirements=requirements,
                          tag='before_trim')

        # Unmount drive to make it possible to format.
        utils.run('umount %s*' % dev, ignore_status=True)
        # Format whole drive to ext4. Mkfs will trim the drive before format.
        utils.run('mkfs.ext4 -F %s' % dev, ignore_status=True)

        # Check write performance
        self.job.run_test('hardware_StorageFio',
                          disable_sysinfo=True,
                          dev=dev,
                          filesize=0,
                          requirements=requirements,
                          tag='after_trim')
    def run_once(self, iters=1, tmout=60 * 60):
        """
        Executes test.

        @param iters: Number of times to run badblocks.
        @param tmout: Time allowed badblocks to run before killing it.
                      (Default time is 60 minutes.)

        """

        # Log starting message.
        logging.info('Statring hardware_Badblocks Test.')
        logging.info('Iterations: %d', iters)
        logging.info('badblocks Timeout (sec): %d', tmout)

        # Determine which device and partition to use.
        logging.info('Determine unused root partition to test on:')
        dev = site_utils.get_free_root_partition()
        logging.info('Testing on ' + dev)

        # Get block device's sector size.
        logging.info('Determine block device sector size:')
        sector_size = self._get_sector_size(site_utils.get_root_device())
        logging.info('Sector size (bytes): ' + sector_size)

        # Get partition size.
        logging.info('Determine partition size:')
        part_size = utils.get_disk_size(dev)
        logging.info('Partition size (bytes): %s', part_size)

        # Run badblocks.
        for i in range(iters):
            logging.info('Starting iteration %d', i)
            self._run_badblocks(dev, sector_size, tmout)

        # Report statistics.
        logging.info('Total pass: %d', self._pass_count)
        logging.info('Total fail: %d', self._fail_count)
        stats = {}
        stats['ea_badblocks_runs'] = iters
        stats['ea_passed_count'] = self._pass_count
        stats['ea_failed_count'] = self._fail_count
        stats['sec_longest_run'] = self._longest_runtime
        # TODO: change write_perf_keyval() to output_perf_value() as soon as
        # autotest is ready for it.
        self.write_perf_keyval(stats)

        # Report test pass/fail.
        if self._pass_count != iters:
            raise error.TestFail('One or more runs found bad blocks on'
                                 ' storage device.')
Beispiel #5
0
    def initialize(self, dev='', filesize=DEFAULT_FILE_SIZE):
        """
        Set up local variables.

        @param dev: block device / file to test.
                Spare partition on root device by default
        @param filesize: size of the file. 0 means whole partition.
                by default, 1GB.
        """
        if dev != '' and (os.path.isfile(dev) or not os.path.exists(dev)):
            if filesize == 0:
                raise error.TestError(
                    'Nonzero file size is required to test file systems')
            self.__filename = dev
            self.__filesize = filesize
            self.__description = ''
            return

        if not dev:
            dev = site_utils.get_fixed_dst_drive()

        if dev == site_utils.get_root_device():
            if filesize == 0:
                raise error.TestError(
                    'Using the root device as a whole is not allowed')
            else:
                self.__filename = site_utils.get_free_root_partition()
        elif filesize != 0:
            # Use the first partition of the external drive
            if dev[5:7] == 'sd':
                self.__filename = dev + '1'
            else:
                self.__filename = dev + 'p1'
        else:
            self.__filename = dev
        self.__get_disk_size()
        self.__get_device_description()

        # Restrict test to use a given file size, default 1GiB
        if filesize != 0:
            self.__filesize = min(self.__filesize, filesize)

        self.__verify_only = False

        logging.info('filename: %s', self.__filename)
        logging.info('filesize: %d', self.__filesize)
    def run_once(self):
        root_dev = site_utils.get_root_device()
        self._device = os.path.basename(root_dev)
        disk_size = utils.get_disk_size(root_dev)
        if not disk_size:
            raise error.TestError('Unable to determine main disk size')

        # Capacity of a hard disk is quoted with SI prefixes, incrementing by
        # powers of 1000, instead of powers of 1024.
        gb = float(disk_size) / (10 ** 9)

        self.write_perf_keyval({"gb_main_disk_size": gb})
        min_gb = self._compute_min_gb()
        logging.info("DiskSize: %.3f GB MinDiskSize: %.3f GB", gb, min_gb)
        if (gb < min_gb):
            raise error.TestError("DiskSize %.3f GB below minimum (%.3f GB)" \
                % (gb, min_gb))
Beispiel #7
0
    def run_once(self,
                 dev='',
                 quicktest=False,
                 requirements=None,
                 integrity=False,
                 wait=60 * 60 * 72):
        """
        Runs several fio jobs and reports results.

        @param dev: block device to test
        @param quicktest: short test
        @param requirements: list of jobs for fio to run
        @param integrity: test to check data integrity
        @param wait: seconds to wait between a write and subsequent verify

        """

        if requirements is not None:
            pass
        elif quicktest:
            requirements = [('1m_write', []), ('16k_read', [])]
        elif integrity:
            requirements = [('8k_async_randwrite', []),
                            ('8k_async_randwrite', [self.VERIFY_OPTION])]
        elif dev in ['', site_utils.get_root_device()]:
            requirements = [
                ('surfing', []),
                ('boot', []),
                ('login', []),
                ('seq_read', []),
                ('seq_write', []),
                ('16k_read', []),
                ('16k_write', []),
                ('1m_stress', []),
            ]
        else:
            # TODO(waihong@): Add more test cases for external storage
            requirements = [
                ('seq_read', []),
                ('seq_write', []),
                ('16k_read', []),
                ('16k_write', []),
                ('1m_stress', []),
            ]

        results = {}
        for job, options in requirements:
            # Keys are labeled according to the test case name, which is
            # unique per run, so they cannot clash
            if self.VERIFY_OPTION in options:
                time.sleep(wait)
                self.__verify_only = True
            else:
                self.__verify_only = False
            env_vars = ' '.join([
                'FILENAME=' + self.__filename,
                'FILESIZE=' + str(self.__filesize),
                'VERIFY_ONLY=' + str(int(self.__verify_only))
            ])
            job_file = os.path.join(self.bindir, job)
            results.update(fio_util.fio_runner(self, job_file, env_vars))

        # Output keys relevant to the performance, larger filesize will run
        # slower, and sda5 should be slightly slower than sda3 on a rotational
        # disk
        self.write_test_keyval({
            'filesize': self.__filesize,
            'filename': self.__filename,
            'device': self.__description
        })
        logging.info('Device Description: %s', self.__description)
        self.write_perf_keyval(results)
        for k, v in results.iteritems():
            if k.endswith('_error'):
                self._fail_count += int(v)
        if self._fail_count > 0:
            raise error.TestFail('%s failed verifications' %
                                 str(self._fail_count))
    def run_once(self, iteration=1, dev=''):
        """
        Read S.M.A.R.T attribute from target device

        @param dev:    target device
        """
        if dev == '':
            logging.info('Run rootdev to determine boot device')
            dev = site_utils.get_root_device()

        logging.info(str('dev: %s' % dev))

        # Skip this test if dev is an eMMC device without raising an error
        if re.match('.*mmc.*', dev):
            logging.info('Target device is an eMMC device. Skip testing')
            self.write_perf_keyval({'device_model': 'eMMC'})
            return

        last_result = ''

        # run multiple time to test the firmware part that retrieve SMART value
        for loop in range(1, iteration + 1):
            cmd = 'smartctl -a -f brief %s' % dev
            result = utils.run(cmd, ignore_status=True)
            exit_status = result.exit_status
            result_text = result.stdout
            result_lines = result_text.split('\n')

            # log all line if line count is different
            # otherwise log only changed line
            if result_text != last_result:
                logging.info(str('Iteration #%d' % loop))
                last_result_lines = last_result.split('\n')
                if len(last_result_lines) != len(result_lines):
                    for line in result_lines:
                        logging.info(line)
                else:
                    for i, line in enumerate(result_lines):
                        if line != last_result_lines[i]:
                            logging.info(line)
                last_result = result_text

            # Ignore error other than first two bits
            if exit_status & 0x3:
                # Error message should be in 4th line of the output
                msg = 'Test failed with error: %s' % result_lines[3]
                raise error.TestFail(msg)

        logging.info(str('smartctl exit status: 0x%x' % exit_status))

        # find drive model
        lookup_table = {}
        pattern = re.compile(self._SMARTCTL_DEVICE_MODEL_PATTERN)
        for line in result_lines:
            if pattern.match(line):
                model = pattern.match(line).group('model')
                for known_model in self._SMARTCTL_LOOKUP_TABLE:
                    if model.startswith(known_model):
                        lookup_table = self._SMARTCTL_LOOKUP_TABLE[known_model]
                        break
                break
        else:
            raise error.TestFail('Can not find drive model')

        # Example of smart ctl result
        # ID# ATTRIBUTE_NAME          FLAGS    VALUE WORST THRESH FAIL RAW_VALUE
        #  12 Power_Cycle_Count       -O----   100   100   000    -    204
        # use flag field to find a valid line
        pattern = re.compile(self._SMARTCTL_RESULT_PATTERN)
        keyval = {}
        fail = []
        for line in result_lines:
            if not pattern.match(line):
                continue
            field = line.split()

            id = int(field[0])
            if id in lookup_table:
                # look up table overwrite smartctl name
                key = lookup_table[id]
            else:
                key = field[1]  # ATTRIBUTE_NAME
                if key == 'Unknown_Attribute':
                    key = "Smart_Attribute_ID_%d" % id

            keyval[key] = field[7]  # RAW_VALUE

            # check for failing attribute
            if field[6] != '-':
                fail += [key]

        if len(keyval) == 0:
            raise error.TestFail(
                'Test failed with error: Can not parse smartctl keyval')

        if len(fail) > 0:
            keyval['fail'] = fail

        keyval['exit_status'] = exit_status
        keyval['device_model'] = model
        self.write_perf_keyval(keyval)