/**
  * Constructor is protected to implement the singleton pattern using 
  * the BlockStorageTest::getTestController static method
  * @param array $options the test options
  */
 protected function BlockStorageTestThroughput($options, $bs = NULL)
 {
     if ($bs === NULL) {
         foreach (array('1024k', '128k') as $bs) {
             if (!isset($options['skip_blocksize']) || !in_array($bs, $options['skip_blocksize'])) {
                 $this->subtests[$bs] = new BlockStorageTestThroughput($options, $bs);
                 $this->subtests[$bs]->purgeAndPrecondition = count($this->subtests[$bs]) > 1;
                 $this->subtests[$bs]->test = 'throughput';
                 $this->subtests[$bs]->verbose = isset($options['verbose']) && $options['verbose'];
                 $this->subtests[$bs]->controller =& $this;
             }
         }
     } else {
         $this->bs = $bs;
         $this->options = $options;
         $this->test = 'throughput';
         foreach ($options['target'] as $target) {
             $device = BlockStorageTest::getDevice($target);
             $device == $target ? $this->deviceTargets = TRUE : ($this->volumeTargets = TRUE);
             break;
         }
     }
 }
 /**
  * validate run options. returns an array populated with error messages 
  * indexed by the argument name. If options are valid, the array returned
  * will be empty
  * @param array $options the run options (see BlockStorageTest::getRunOptions)
  * @return array
  */
 public static function validateRunOptions($options)
 {
     $validate = array('active_range' => array('min' => 1, 'max' => 100), 'font_size' => array('min' => 6, 'max' => 64), 'oio_per_thread' => array('min' => 1, 'max' => 256), 'output' => array('write' => TRUE), 'precondition_passes' => array('min' => 1, 'max' => 5), 'skip_blocksize' => array('option' => array('1m', '128k', '64k', '32k', '16k', '8k', '512b')), 'skip_workload' => array('option' => array('100/0', '95/5', '65/35', '50/50', '35/65', '5/95')), 'ss_max_rounds' => array('min' => 5, 'max' => 100), 'ss_verification' => array('min' => 1, 'max' => 100), 'target' => array('required' => TRUE, 'write' => TRUE), 'test' => array('option' => BlockStorageTest::getSupportedTests(), 'required' => TRUE), 'threads' => array('min' => 1), 'threads_per_core_max' => array('min' => 1), 'threads_per_target_max' => array('min' => 1), 'timeout' => array('min' => 3600), 'trim_offset_end' => array('min' => 1), 'wd_test_duration' => array('min' => 10));
     if (!($valid = validate_options($options, $validate))) {
         $devices = 0;
         $volumes = 0;
         // device and volume type targets cannot be mixed
         foreach ($options['target'] as $target) {
             $device = BlockStorageTest::getDevice($target);
             $device == $target ? $devices++ : $volumes++;
         }
         if ($devices && $volumes) {
             $valid = array('target' => 'Device and volume type targets cannot be mixed');
         }
         // validate collectd rrd options
         if (isset($options['collectd_rrd'])) {
             if (!ch_check_sudo()) {
                 $valid['collectd_rrd'] = 'sudo privilege is required to use this option';
             } else {
                 if (!is_dir($options['collectd_rrd_dir'])) {
                     $valid['collectd_rrd_dir'] = sprintf('The directory %s does not exist', $options['collectd_rrd_dir']);
                 } else {
                     if (shell_exec('ps aux | grep collectd | wc -l') * 1 < 2) {
                         $valid['collectd_rrd'] = 'collectd is not running';
                     } else {
                         if (shell_exec(sprintf('find %s -maxdepth 1 -type d 2>/dev/null | wc -l', $options['collectd_rrd_dir'])) * 1 < 2) {
                             $valid['collectd_rrd_dir'] = sprintf('The directory %s is empty', $options['collectd_rrd_dir']);
                         }
                     }
                 }
             }
         }
     }
     return $valid;
 }