Index: client/tests/wb_kupdate/wb_kupdate.py |
diff --git a/client/tests/wb_kupdate/wb_kupdate.py b/client/tests/wb_kupdate/wb_kupdate.py |
new file mode 100644 |
index 0000000000000000000000000000000000000000..9d77ed8f2cbde50fc9842229630c3ce99cef06ce |
--- /dev/null |
+++ b/client/tests/wb_kupdate/wb_kupdate.py |
@@ -0,0 +1,269 @@ |
+import datetime, logging, os, time |
+from autotest_lib.client.bin import test, utils |
+from autotest_lib.client.common_lib import error |
+ |
+class wb_kupdate(test.test): |
+ version = 1 |
+ |
+ |
+ def _check_parameters(self, mount_point, write_size, file_count, |
+ old_cleanup=False): |
+ """ |
+ Check all test parameters. |
+ |
+ @param mount_point: the path to the desired mount_point. |
+ @param write_size: the size of data in MB to write. |
+ @param file_count: the number of files to write. |
+ @param old_cleanup: removes previous mount_point if it exists and is |
+ not mounted. Default is False. |
+ """ |
+ # Check mount_point. |
+ if not os.path.exists(mount_point): |
+ logging.info('%s does not exist. Creating directory.', mount_point) |
+ elif not os.path.ismount(mount_point) and old_cleanup: |
+ logging.info('Removing previous mount_point directory') |
+ os.rmdir(mount_point) |
+ logging.info('Creating new mount_point.') |
+ else: |
+ raise error.TestError('Mount point: %s already exists.' % |
+ mount_point) |
+ |
+ os.makedirs(mount_point) |
+ # Check write_size > 0. |
+ if not (write_size > 0): |
+ raise error.TestError('Write size should be a positive integer.') |
+ |
+ # Check file_count > 0. |
+ if not (file_count > 0) : |
+ raise error.TestError('File count shoulde be a positive integer.') |
+ |
+ |
+ def _reset_device(self): |
+ """ |
+ Reset the test. Reinitialize sparse file. |
+ """ |
+ # Umount device. |
+ logging.debug('Cleanup - unmounting loopback device.') |
+ utils.system('umount %s' % self.mount_point, ignore_status=True) |
+ |
+ # Remove sparse_file. |
+ logging.debug('Cleanup - removing sparse file.') |
+ os.remove(self.sparse_file) |
+ |
+ # Remove mount_point directory. |
+ logging.debug('Cleanup - removing the mount_point.') |
+ os.rmdir(self.mount_point) |
+ |
+ |
+ def _create_partition(self): |
+ """ |
+ Create and initialize the sparse file. |
+ """ |
+ # Recreate sparse_file. |
+ utils.system('dd if=/dev/zero of=%s bs=1M seek=1024 count=1' % |
+ self.sparse_file) |
+ |
+ # Format sparse_file. |
+ utils.system('echo "y" | mkfs -t %s %s' % |
+ (self.file_system, self.sparse_file)) |
+ |
+ # Mount sparse_file. |
+ utils.system('mount -o loop -t %s %s %s' % |
+ (self.file_system, self.sparse_file, self.mount_point)) |
+ |
+ |
+ def _needs_more_time(self, start_time, duration, _now=None): |
+ """ |
+ Checks to see if the test has run its course. |
+ |
+ @param start_time: a datetime object specifying the start time of the |
+ test. |
+ @param duration: test duration in minutes. |
+ @param _now: used mostly for testing - ensures that the function returns |
+ pass/fail depnding on the value of _now. |
+ |
+ @return: True if the test still needs to run longer. |
+ False if the test has run for 'duration' minutes. |
+ """ |
+ if not _now: |
+ time_diff = datetime.datetime.now() - start_time |
+ else: |
+ time_diff = _now - start_time |
+ return time_diff <= datetime.timedelta(seconds=duration*60) |
+ |
+ |
+ def _write_data(self, destination, counter, write_size): |
+ """ |
+ Writes data to the cache/memory. |
+ |
+ @param destination: the absolute path to where the data needs to be |
+ written. |
+ @param counter: the file counter. |
+ @param write_size: the size of data to be written. |
+ |
+ @return: the time when the write completed as a datetime object. |
+ """ |
+ # Write data to disk. |
+ file_name = os.path.join(destination, 'test_file_%s' % counter) |
+ write_cmd = ('dd if=/dev/zero of=%s bs=1M count=%s' % |
+ (file_name, write_size)) |
+ utils.system(write_cmd) |
+ |
+ # Time the write operation. |
+ write_completion_time = datetime.datetime.now() |
+ |
+ # Return write completion time. |
+ return write_completion_time |
+ |
+ |
+ def _get_disk_usage(self, file_name): |
+ """ |
+ Returns the disk usage of given file. |
+ |
+ @param file_name: the name of the file. |
+ |
+ @return: the disk usage as an integer. |
+ """ |
+ # Check du stats. |
+ cmd = '%s %s' % (self._DU_CMD, file_name) |
+ |
+ # Expected value for output = '1028\tfoo' |
+ output = utils.system_output(cmd) |
+ |
+ # Desired ouput = (1028, foo) |
+ output = output.split('\t') |
+ |
+ return int(output[0]) |
+ |
+ |
+ def _wait_until_data_flushed(self, start_time, max_wait_time): |
+ """ |
+ Check to see if the sparse file size increases. |
+ |
+ @param start_time: the time when data was actually written into the |
+ cache. |
+ @param max_wait_time: the max amount of time to wait. |
+ |
+ @return: time waited as a datetime.timedelta object. |
+ """ |
+ current_size = self._get_disk_usage(self.sparse_file) |
+ flushed_size = current_size |
+ |
+ logging.debug('current_size: %s' % current_size) |
+ logging.debug('flushed_size: %s' % flushed_size) |
+ |
+ # Keep checking until du value changes. |
+ while current_size == flushed_size: |
+ # Get flushed_size. |
+ flushed_size = self._get_disk_usage(self.sparse_file) |
+ logging.debug('flushed_size: %s' % flushed_size) |
+ time.sleep(1) |
+ |
+ # Check if data has been synced to disk. |
+ if not self._needs_more_time(start_time, max_wait_time): |
+ raise error.TestError('Data not flushed. Waited for %s minutes ' |
+ 'for data to flush out.' % max_wait_time) |
+ |
+ # Return time waited. |
+ return datetime.datetime.now() - start_time |
+ |
+ |
+ def initialize(self): |
+ """ |
+ Initialize all private and global member variables. |
+ """ |
+ self._DU_CMD = 'du' |
+ self.partition = None |
+ self.mount_point = '' |
+ self.sparse_file = '' |
+ self.result_map = {} |
+ self.file_system = None |
+ |
+ |
+ def run_once(self, mount_point, file_count, write_size, |
+ max_flush_time=1, file_system=None, remove_previous=False, |
+ sparse_file=os.path.join(os.getcwd(),'sparse_file'), |
+ old_cleanup=False): |
+ """ |
+ Control execution of the test. |
+ |
+ @param mount_point: the absolute path to the mount point. |
+ @param file_count: the number of files to write. |
+ @param write_size: the size of each file in MB. |
+ @param max_flush_time: the maximum time to wait for the writeback to |
+ flush dirty data to disk. Default = 1 minute. |
+ @param file_system: the new file system to be mounted, if any. |
+ Default = None. |
+ @param remove_previous: boolean that allows the removal of previous |
+ files before creating a new one. Default = False. |
+ @param sparse_file: the absolute path to the sparse file. |
+ @param old_cleanup: removes previous mount_point if it exists and is |
+ not mounted. Default is False. |
+ """ |
+ # Check validity of parameters. |
+ self._check_parameters(mount_point, write_size, file_count, |
+ old_cleanup) |
+ |
+ # Initialize class variables. |
+ self.mount_point = mount_point |
+ self.sparse_file = sparse_file |
+ self.file_system = file_system |
+ |
+ # Initialize partition values. |
+ self._create_partition() |
+ |
+ # Flush read and write cache. |
+ utils.drop_caches() |
+ |
+ # Start iterations. |
+ logging.info('Starting test operations.') |
+ test_start_time = datetime.datetime.now() |
+ counter = 1 |
+ |
+ # Run test until file_count files are successfully written to disk. |
+ while counter < file_count: |
+ logging.info('Iteration %s.', counter) |
+ |
+ # Write data to disk. |
+ write_completion_time = self._write_data(self.mount_point, counter, |
+ write_size) |
+ logging.debug('Write time:%s', |
+ write_completion_time.strftime("%H:%M:%S")) |
+ |
+ # Wait until data get synced to disk. |
+ time_taken = self._wait_until_data_flushed(write_completion_time, |
+ max_flush_time) |
+ |
+ # Log time statistics. |
+ logging.info('Time taken to flush data: %s seconds.', |
+ time_taken.seconds) |
+ |
+ # Check if there is a need to remove the previously written file. |
+ if remove_previous: |
+ logging.debug('Removing previous file instance.') |
+ os.remove(file_name) |
+ else: |
+ logging.debug('Not removing previous file instance.') |
+ |
+ # Flush cache. |
+ logging.debug('Flush cache between iterations.') |
+ utils.drop_caches() |
+ |
+ # Update the result map. |
+ self.result_map[counter] = time_taken.seconds |
+ |
+ # Increment the counter. |
+ counter += 1 |
+ |
+ |
+ def postprocess(self): |
+ """ |
+ Cleanup routine. |
+ """ |
+ # Write out keyval map. |
+ self.write_perf_keyval(self.result_map) |
+ |
+ # Cleanup device. |
+ self._reset_device() |
+ |
+ logging.info('Test operations completed.') |