/** * exec method with the same interface as that in KWUtils, will simulate * an execution of the condor_submit_dag executable for a few select test cases. * * @param string $command * @param null|mixed $output * @param string $chdir * @param null|mixed $return_val * @throws Zend_Exception */ public function exec($command, &$output = null, $chdir = '', &$return_val = null) { // just doing the same things as the actual KWUtils exec to check // that this function will work the same as the exec function other // than the actual exec system call if (!empty($chdir) && is_dir($chdir)) { if (!chdir($chdir)) { throw new Zend_Exception('Failed to change directory: [' . $chdir . ']'); } } // on Linux need to add redirection to handle stderr $command = KWUtils::escapeCommand($command); // all test cases should have the proper syntax, verify this if (!preg_match('/' . MIDAS_BATCHMAKE_CONDOR_SUBMIT_DAG . ".*\\'(\\S*)\\'/", $command, $matches)) { throw new Zend_Exception('malformed condor_submit_dag command'); } $scriptName = $matches[1]; if (preg_match('/CompileReturnNonzero.dagjob/', $scriptName)) { $return_val = -1; $output = array('1 error', '1'); } elseif (preg_match('/Compiles.dagjob/', $scriptName)) { // do a bit of checking // ensure the $scriptName exists in the $chdir if (!file_exists($chdir . '/' . $scriptName)) { $return_val = -1; $output = array('1 error can not find ' . $chdir . '/' . $scriptName, '1'); return; } $return_val = 0; $output = array(''); } else { throw new Zend_Exception('Unexpected dagjob test script: ' . $scriptName); } }
/** clean up after tests */ public function tearDown() { // remove the temporary tests dir $testTmpDir = $this->getTempDirectory() . '/batchmake/tests'; KWUtils::recursiveRemoveDirectory($testTmpDir); // change the current dir back to the saved cwd after each test chdir($this->cwd); }
/** clean up after tests */ public function tearDown() { // remove the temporary tests dir $tmpDir = $this->getTempDirectory() . '/' . $this->testTmpDir; KWUtils::recursiveRemoveDirectory($tmpDir); $this->Item->delete($this->tmpItem); // change the current dir back to the saved cwd after each test chdir($this->cwd); }
/** * exports a list of itemIds to a work dir. * * @param UserDao $userDao * @param Batchmake_TaskDao $taskDao * @param array $itemIds * @throws Zend_Exception */ public function exportItemsToWorkDataDir($userDao, $taskDao, $itemIds) { // export the items to the work dir data dir $datapath = $taskDao->getWorkDir() . '/' . 'data'; if (!KWUtils::mkDir($datapath)) { throw new Zend_Exception("couldn't create data export dir: " . $datapath); } /** @var ExportComponent $exportComponent */ $exportComponent = MidasLoader::loadComponent('Export'); $symlink = true; $exportComponent->exportBitstreams($userDao, $datapath, $itemIds, $symlink); }
/** * exec method with the same interface as that in KWUtils, will check the * command and intercept it if it is a known command with a Mock object * that should be used for testing, otherwise it will pass it on to KWUtils. * * @param type $command * @param type $output * @param type $chdir * @param type $return_val */ public function exec($command, &$output = null, $chdir = '', &$return_val = null) { $matched = false; foreach ($this->mockExes as $exeName => $mockExe) { if (preg_match('/' . $exeName . '/', $command)) { $matched = true; $mockExe->exec($command, $output, $chdir, $return_val); } } if (!$matched) { KWUtils::exec($command, $output, $chdir, $return_val); } }
/** * function will create a temporary batchmake config, copying over test data * to the the locations in that config needed for the tests, returning an * array of config property names to directory locations. * * @todo figure out a way to copy over Batchmake or else mock it * @return array * @throws Zend_Exception */ public function setupAndGetConfig() { // create a test batchmake setup in the temp dir // and initialize test data $tmpDir = $this->getTempDirectory(); $subDirs = array('batchmake', 'tests'); KWUtils::createSubDirectories($tmpDir . '/', $subDirs); $configProps = array(MIDAS_BATCHMAKE_TMP_DIR_PROPERTY => $tmpDir . '/batchmake/tests/tmp', MIDAS_BATCHMAKE_BIN_DIR_PROPERTY => $tmpDir . '/batchmake/tests/bin', MIDAS_BATCHMAKE_SCRIPT_DIR_PROPERTY => $tmpDir . '/batchmake/tests/script', MIDAS_BATCHMAKE_APP_DIR_PROPERTY => $tmpDir . '/batchmake/tests/bin', MIDAS_BATCHMAKE_DATA_DIR_PROPERTY => $tmpDir . '/batchmake/tests/data', MIDAS_BATCHMAKE_CONDOR_BIN_DIR_PROPERTY => $tmpDir . '/batchmake/tests/condorbin'); // now make sure these dirs exist // later can actually add some stuff to these dirs foreach ($configProps as $dir) { if (!file_exists($dir) && !KWUtils::mkDir($dir)) { throw new Zend_Exception("couldn't create dir " . $dir); } } // now copy over the bms files $srcDir = BASE_PATH . 'modules/batchmake/tests/testfiles/script'; $targetDir = $configProps[MIDAS_BATCHMAKE_SCRIPT_DIR_PROPERTY]; $extension = '.bms'; $this->symlinkFileset($srcDir, $targetDir, $extension); // and now the bmms $srcDir = BASE_PATH . 'modules/batchmake/tests/testfiles/bin'; $targetDir = $configProps[MIDAS_BATCHMAKE_APP_DIR_PROPERTY]; $extension = '.bmm'; $this->symlinkFileset($srcDir, $targetDir, $extension); // the mock object strategy requires both an interface and for // executable files to exist on disk in a particular location, // so here we will create symlinks to a known executable // ls // which should be on most systems $params = array('ls'); $cmd = KWUtils::prepareExeccommand('which', $params); // dir doesn't matter, just send in srcDir as it is convenient KWUtils::exec($cmd, $output, $srcDir, $returnVal); if ($returnVal !== 0 || !isset($output) || !isset($output[0])) { throw new Zend_Exception('Problem finding ls on your system, used for testing'); } $pathToLs = $output[0]; // get the applications and their path properties from the component that // expects them $applicationsPaths = Batchmake_KWBatchmakeComponent::getApplicationsPaths(); foreach ($applicationsPaths as $application => $pathProperty) { // now in the place of each executable, symlink the ls exe $link = $configProps[$pathProperty] . '/' . $application; if (!file_exists($link) && !symlink($pathToLs, $link)) { throw new Zend_Exception($pathToLs . ' could not be sym-linked to ' . $link); } } return $configProps; }
/** * Create a task. * * @param UserDao $userDao * @param string $tmpWorkDirRoot * @return Batchmake_TaskDao * @throws Zend_Exception */ public function createTask($userDao, $tmpWorkDirRoot) { if (!$userDao instanceof UserDao) { throw new Zend_Exception('Error parameters.'); } /** @var Batchmake_TaskDao $task */ $task = MidasLoader::newDao('TaskDao', 'batchmake'); $task->setUserId($userDao->getKey()); $this->save($task); $userId = $task->getUserId(); $taskId = $task->getKey(); $subdirs = array(MIDAS_BATCHMAKE_SSP_DIR, $userId, $taskId); // create a workDir based on the task and user $workDir = KWUtils::createSubDirectories($tmpWorkDirRoot . '/', $subdirs); $task->setWorkDir($workDir); $this->save($task); return $task; }
/** * has the same interface as KWUtils.exec, used to simulate a BatchMake * executable for testing. * * @param string $command * @param null|mixed $output * @param string $chdir * @param null|mixed $return_val * @throws Zend_Exception */ public function exec($command, &$output = null, $chdir = '', &$return_val = null) { // just doing the same things as the actual KWUtils exec to check // that this function will work the same as the exec function other // than the actual exec system call if (!empty($chdir) && is_dir($chdir)) { if (!chdir($chdir)) { throw new Zend_Exception('Failed to change directory: [' . $chdir . ']'); } } $command = KWUtils::escapeCommand($command); // now look for particular commands that this Mock object can service if (preg_match('/' . $this->compileFlag . '/', $command)) { $this->execCompile($command, $output, $chdir, $return_val); } elseif (preg_match('/' . $this->generateDagFlag . '/', $command)) { $this->execGenerateCondorDag($command, $output, $chdir, $return_val); } else { throw new Zend_Exception('unexepected BatchMake command flag:' . $command); } }
/** Test that TaskModel::createTask($userDao) works */ public function testCreateTask() { $usersFile = $this->loadData('User', 'default', '', 'batchmake'); /** @var Batchmake_TaskModel $taskModel */ $taskModel = MidasLoader::loadModel('Task', 'batchmake'); $user1Dao = $usersFile[0]; $tmpWorkDirRoot = $this->getTempDirectory() . '/' . 'test'; KWUtils::mkDir($tmpWorkDirRoot); $task1Dao = $taskModel->createTask($user1Dao, $tmpWorkDirRoot); $this->assertNotEmpty($task1Dao); $this->assertTrue($task1Dao instanceof Batchmake_TaskDao); $userId1 = $task1Dao->getUserId(); $this->assertTrue(is_numeric($userId1)); $this->assertFalse(is_object($userId1)); $this->assertEquals($userId1, $user1Dao->getUserId()); $taskId1 = $task1Dao->getKey(); $this->assertTrue(is_numeric($taskId1)); $this->assertFalse(is_object($taskId1)); // now try a different user $user2Dao = $usersFile[1]; $task2Dao = $taskModel->createTask($user2Dao, $tmpWorkDirRoot); $this->assertNotEmpty($task2Dao); $this->assertTrue($task2Dao instanceof Batchmake_TaskDao); $userId2 = $task2Dao->getUserId(); $this->assertTrue(is_numeric($userId2)); $this->assertFalse(is_object($userId2)); $this->assertEquals($userId2, $user2Dao->getUserId()); $taskId2 = $task2Dao->getKey(); $this->assertTrue(is_numeric($taskId2)); $this->assertFalse(is_object($taskId2)); // make sure each of the tasks got a different id $this->assertNotEquals($taskId1, $taskId2); // now try to retrieve it by key $task3Dao = $taskModel->load($taskId1); $this->assertTrue($taskModel->compareDao($task1Dao, $task3Dao)); $task4Dao = $taskModel->load($taskId2); $this->assertTrue($taskModel->compareDao($task2Dao, $task4Dao)); }
/** * Test ExportComponentTest::exportBitstreams function using invalid input. * * test case 1) input parameter itemIds is not an array; expect an exception * test case 2) use valid item id with invalid revision number; expect an exception * test case 3) use invalid item id; expect an exception */ public function testExportBitStreamsInvalidCases() { $midas_exporttest_dir = $this->getTempDirectory() . '/exportTest'; $usersFile = $this->loadData('User', 'default'); $userDao = $this->User->load($usersFile[0]->getKey()); $this->uploadItems($userDao); require_once BASE_PATH . '/core/controllers/components/ExportComponent.php'; $exportCompoenent = new ExportComponent(); $validFile = 'public.file'; $validItems = $this->Item->getItemsFromSearch($validFile, $userDao); $validItemId = $validItems[0]->getKey(); $invalidRevision = 100; $invalidItemId = 99999; // test case 1) try { $exportCompoenent->exportBitstreams($userDao, $midas_exporttest_dir, $validItemId, true); $this->fail('Expected an exception exporting component, but didn not get one'); } catch (Zend_Exception $ze) { // if we got here, this is the correct behavior $this->assertTrue(true); } // test case 2) $inputItemIds = array(); $inputItemIds[] = $validItemId . ',' . $invalidRevision; try { $exportCompoenent->exportBitstreams($userDao, $midas_exporttest_dir, $inputItemIds, true); $this->fail('Expected an exception exporting component, but did not get one'); } catch (Zend_Exception $ze) { // if we got here, this is the correct behavior $this->assertTrue(true); } // test case 3) $inputItemIds = array(); $inputItemIds[] = $invalidItemId; try { $exportCompoenent->exportBitstreams($userDao, $midas_exporttest_dir, $inputItemIds, true); $this->fail('Expected an exception exporting component, but did not get one'); } catch (Zend_Exception $ze) { // if we got here, this is the correct behavior $this->assertTrue(true); } // clean up KWUtils::recursiveRemoveDirectory($midas_exporttest_dir); }
/** * will submit the passed in $dagScript to condor, * executing in the passed in $workDir. * * @param string $workDir * @param string $dagScript * @throws Zend_Exception */ public function condorSubmitDag($workDir, $dagScript) { // Prepare command $params = array($dagScript); $cmd = KWUtils::prepareExecCommand($this->configCondorBinDir . '/' . MIDAS_BATCHMAKE_CONDOR_SUBMIT_DAG, $params); // Run command $this->executor->exec($cmd, $output, $workDir, $returnVal); if ($returnVal !== 0) { throw new Zend_Exception('condorSubmitDag: Failed to run: [' . $cmd . '], output: [' . implode(',', $output) . ']'); } }
/** * Stop DICOM server. * * @path /dicomserver/server/stop * @http POST * @param storescp_cmd (Optional) The command to run storescp * @param dcmqrscp_cmd (Optional) The command to run dcmqrscp * @param incoming_dir (Optional) The incoming directory to receive and process DICOM files * @param get_command (Optional) If set, will not stop DICOM server, but only get command used to stop DICOM server in command line. * @return */ public function stop($args) { // Only administrator can call this api $userDao = Zend_Registry::get('userSession')->Dao; if (!$userDao || !$userDao->isAdmin()) { throw new Exception('Only administrator can stop DICOM server', MIDAS_INVALID_POLICY); } $ret = array(); $status_args = array(); if (!empty($args['storescp_cmd'])) { $status_args['storescp_cmd'] = $args['storescp_cmd']; } if (!empty($args['dcmqrscp_cmd'])) { $status_args['dcmqrscp_cmd'] = $args['dcmqrscp_cmd']; } $running_status = $this->status($status_args); if ($running_status['status'] == MIDAS_DICOMSERVER_SERVER_NOT_RUNNING && !array_key_exists('get_command', $args)) { $ret['message'] = 'DICOM server is not running now!'; return $ret; } $storescp_cmd = 'storescp'; if (!empty($args['storescp_cmd'])) { $storescp_cmd = $args['storescp_cmd']; } $dcmqrscp_cmd = 'dcmqrscp'; if (!empty($args['dcmqrscp_cmd'])) { $dcmqrscp_cmd = $args['dcmqrscp_cmd']; } if (!empty($args['incoming_dir'])) { $incoming_dir = $args['incoming_dir']; } else { /** @var Dicomserver_ServerComponent $serverComponent */ $serverComponent = MidasLoader::loadComponent('Server', 'dicomserver'); $incoming_dir = $serverComponent->getDefaultReceptionDir(); } $log_dir = $incoming_dir . MIDAS_DICOMSERVER_LOGS_DIRECTORY; if (!file_exists($log_dir)) { KWUtils::mkDir($log_dir, 0777); } $python_cmd = 'python'; $python_params = array(); $python_params[] = BASE_PATH . '/modules/dicomserver/library/serverWrapper.py'; $python_params[] = '--stop'; $python_params[] = '-i ' . $incoming_dir; $python_params[] = '-s ' . $storescp_cmd; $python_params[] = '-q ' . $dcmqrscp_cmd; $stop_server_command = KWUtils::prepareExeccommand($python_cmd, $python_params); if (array_key_exists('get_command', $args)) { $stop_server_command_string = str_replace("'", '', $stop_server_command); return escapeshellarg($stop_server_command_string); } KWUtils::exec($stop_server_command, $output, '', $returnVal); $ret['message'] = 'Succeeded to stop DICOM C-STORE receiver and Query-Retrieve services!'; if ($returnVal) { $exception_string = "Failed to stop DICOM server! \n Reason:" . implode("\n", $output); throw new Zend_Exception(htmlspecialchars($exception_string, ENT_QUOTES), MIDAS_INVALID_POLICY); } return $ret; }
/** * Use thumbnailer to pre-process a bitstream to generate a jpeg file. * Echoes an error message if a problem occurs (for the scheduler log). * * @param string $name name of the image to be pre-processed * @param string $fullPath absolute path to the image to be pre-processed * @return string * @throws Zend_Exception */ public function preprocessByThumbnailer($name, $fullPath) { $tmpPath = UtilityComponent::getTempDirectory('thumbnailcreator'); if (!file_exists($tmpPath)) { throw new Zend_Exception('Temporary thumbnail dir does not exist: ' . $tmpPath); } $copyDestination = $tmpPath . '/' . $name; copy($fullPath, $copyDestination); $jpegDestination = $tmpPath . '/' . $name . '.jpg'; /** @var RandomComponent $randomComponent */ $randomComponent = MidasLoader::loadComponent('Random'); while (file_exists($jpegDestination)) { $jpegDestination = $tmpPath . '/' . $name . $randomComponent->generateInt() . '.jpg'; } /** @var SettingModel $settingModel */ $settingModel = MidasLoader::loadModel('Setting'); $thumbnailerPath = $settingModel->getValueByName(MIDAS_THUMBNAILCREATOR_THUMBNAILER_KEY, $this->moduleName); $thumbnailerParams = array($copyDestination, $jpegDestination); $thumbnailerCmd = KWUtils::prepareExeccommand($thumbnailerPath, $thumbnailerParams); if (KWUtils::isExecutable($thumbnailerPath)) { KWUtils::exec($thumbnailerCmd); } else { unlink($copyDestination); throw new Zend_Exception('Thumbnailer does not exist or you do not have execute permission. Please check the configuration of thumbnailcreator module.'); } if (!file_exists($jpegDestination)) { unlink($copyDestination); throw new Zend_Exception('Problem executing thumbnailer on your system'); } else { unlink($copyDestination); return $jpegDestination; } }
/** * Register DICOM image files (bitstreams). */ public function register($revision) { $bitstreams = $revision->getBitstreams(); if (count($bitstreams) < 1) { return; } /** @var SettingModel $settingModel */ $settingModel = MidasLoader::loadModel('Setting'); $command = $settingModel->getValueByName(MIDAS_DICOMSERVER_DCMQRIDX_COMMAND_KEY, $this->moduleName); $command = str_replace("'", '', $command); $commandParams = array(); $receptionDirectory = $settingModel->getValueByName(MIDAS_DICOMSERVER_RECEPTION_DIRECTORY_KEY, $this->moduleName); if (!is_writable($receptionDirectory)) { throw new Zend_Exception('Please configure Dicom Server module correctly. Its reception directory is NOT writable!', MIDAS_INVALID_POLICY); } $aeStorage = $receptionDirectory . MIDAS_DICOMSERVER_PACS_DIRECTORY; $aeStorage = str_replace("'", '', $aeStorage); $commandParams[] = $aeStorage; foreach ($bitstreams as $bitstream) { $commandParams[] = $bitstream->getFullPath(); $registerCommand = KWUtils::prepareExeccommand($command, $commandParams); array_pop($command_params); // prepare for next iteration in the loop KWUtils::exec($registerCommand, $output, '', $returnVal); if ($returnVal) { $exceptionString = "Failed to register DICOM images! \n Reason:" . implode("\n", $output); throw new Zend_Exception(htmlspecialchars($exceptionString, ENT_QUOTES), MIDAS_INVALID_POLICY); } } /** @var Dicomserver_RegistrationModel $registrationModel */ $registrationModel = MidasLoader::loadModel('Registration', 'dicomserver'); $itemId = $revision->getItemId(); if (!$registrationModel->checkByItemId($itemId)) { $registrationModel->createRegistration($itemId); } }
/** tests recursiveRemoveDirectory function */ public function testRecursiveRemoveDirectory() { // test some basic exception handling $this->assertFalse(KWUtils::recursiveRemoveDirectory('')); $this->assertFalse(KWUtils::recursiveRemoveDirectory('thisstringisunlikelytobeadirectory')); // create a two-level directory $testParentDir = UtilityComponent::getTempDirectory() . '/KWUtilsParentDir'; mkdir($testParentDir); $testChildDir = UtilityComponent::getTempDirectory() . '/KWUtilsParentDir/ChildDir'; mkdir($testChildDir); copy(BASE_PATH . '/tests/testfiles/search.png', $testChildDir . '/testContent.png'); $this->assertTrue(file_exists($testChildDir . '/testContent.png')); // recursively remove the directory KWUtils::recursiveRemoveDirectory($testParentDir); $this->assertFalse(file_exists($testParentDir)); }
/** * Export bitstreams to target directory. * * Given itemIds, do policy check on these itemIds, * then create symbolic links to bitstreams (or copy the bitstreams) * in the "{targetDir}/{itemId}/" directories. If the {itemId} subdirectory * has been existed, delete the existing one first. * For policy check, we only check if the items are readable by the given user, * and don't further distinguish among "can_read", "can_write", and "owner" * levels. * * @param UserDao $userDao * @param string $targetDir Target directory to export bitstreams * @param array $itemIds Array of itemIds. * Each element is a comma separated value, * the 1st column is the actual item_id, * the 2nd is revision_number (optional) * @param bool $shouldSymLink Should we create symbolic links? * If not, the bitstreams will be copied to the target directory * @throws Zend_Exception */ public function exportBitstreams($userDao, $targetDir, $itemIds, $shouldSymLink) { // if the path has a slash at the end, remove it here $targetDir = rtrim($targetDir, '/'); /** @var ItemModel $itemModel */ $itemModel = MidasLoader::loadModel('Item'); // Get items $revisions = array(); if (!is_array($itemIds)) { throw new Zend_Exception('Input parameter $itemIds should be an array.'); } if (!empty($itemIds)) { foreach ($itemIds as $itemId) { // $itemId is a comma separated value, // the 1st column is the actual item_id, the 2nd is revision_num (optional) $tmpId = explode(',', $itemId); if (empty($tmpId[0])) { continue; } // delete the itemId directory if it exists which means it was exported by // other user before $item_export_dir = $targetDir . '/' . $itemId; if (file_exists($item_export_dir)) { if (!KWUtils::recursiveRemoveDirectory($item_export_dir)) { throw new Zend_Exception($item_export_dir . ' has already existed and we cannot delete it.'); } } $item = $itemModel->load($tmpId[0]); if ($item == false) { throw new Zend_Exception('Item ' . $tmpId[0] . ' does not exist. Please check your input.'); } elseif (!$itemModel->policyCheck($item, $userDao)) { // Do policy check in the ITEM level, ignore items which cannot be exported by the user. continue; } // Use the given revision_number if it is not empty if (isset($tmpId[1])) { $revision = $itemModel->getRevision($item, $tmpId[1]); if ($revision !== false) { $revisions[] = $revision; } else { throw new Zend_Exception('Revision number ' . $tmpId[1] . ' for item ' . $tmpId[0] . ' does not exist. Please check your input.'); } } else { // Otherwise use the latest revision $revision = $itemModel->getLastRevision($item); if ($revision !== false) { $revisions[] = $revision; } } } } // process the items which pass the ITEM level policy check if (!empty($revisions)) { /** @var RandomComponent $randomComponent */ $randomComponent = MidasLoader::loadComponent('Random'); foreach ($revisions as $revision) { $itemId = $revision->getItemId(); $this->_createItemDirectory($targetDir . '/' . $itemId); // itemRevision -> bitstream is a one-to-many relation (in bitstream table) $bitstreams = $revision->getBitstreams(); if (!empty($bitstreams)) { foreach ($bitstreams as $bitstream) { // if the bitstream is not an actual file, such as url type, skip it if ($bitstream->getChecksum() == ' ') { continue; } $source = $bitstream->getAssetstore()->getPath() . '/' . $bitstream->getPath(); $dest = $targetDir . '/' . $itemId . '/' . $bitstream->getName(); // create symbolic links in target directory if ($shouldSymLink) { // for symbolic link option,if multiple bitstreams (in a single item revision) // have the same file name, add a '.new' suffix to distinguish them if (file_exists($dest)) { $dest .= '.' . $randomComponent->generateInt() . '.new'; } if (!symlink($source, $dest)) { throw new Zend_Exception('Cannot create symlink: ' . $dest . 'linked to' . $source); } } else { // OR copy bitstreams to target directory // for copy option, if multiple bitstreams (in a single item revision) // have the same file name, new file(s) wil overwrite the existing file(s) if (!copy($source, $dest)) { throw new Zend_Exception('Cannot copy bitstream from: ' . $source . 'to: ' . $dest); } } } } } } }
/** * forwards a call to this method on to KWUtils.exec, with the same * method signature. * * @param string $command * @param null|mixed $output * @param string $chdir * @param null|mixed $return_val * @throws Zend_Exception */ public function exec($command, &$output = null, $chdir = '', &$return_val = null) { KWUtils::exec($command, $output, $chdir, $return_val); }