From cb481742663ea96fe4163bcceb777307e1bd8b8c Mon Sep 17 00:00:00 2001 From: "Eloy Lafuente (stronk7)" Date: Sat, 14 Apr 2012 05:03:13 +0200 Subject: [PATCH 1/2] MDL-32587 phpunit: new option to create distributed phpunit.xml files --- admin/tool/phpunit/cli/util.php | 28 ++++-- lib/phpunit/lib.php | 164 ++++++++++++++++++++++++++++++++ 2 files changed, 183 insertions(+), 9 deletions(-) diff --git a/admin/tool/phpunit/cli/util.php b/admin/tool/phpunit/cli/util.php index cced963ecf2..137e9183a23 100644 --- a/admin/tool/phpunit/cli/util.php +++ b/admin/tool/phpunit/cli/util.php @@ -34,13 +34,14 @@ require_once(__DIR__.'/../../../../lib/phpunit/bootstraplib.php'); // now get cli options list($options, $unrecognized) = cli_get_params( array( - 'drop' => false, - 'install' => false, - 'buildconfig' => false, - 'diag' => false, - 'phpunitdir' => false, - 'run' => false, - 'help' => false, + 'drop' => false, + 'install' => false, + 'buildconfig' => false, + 'buildconfigdist' => false, + 'diag' => false, + 'phpunitdir' => false, + 'run' => false, + 'help' => false, ), array( 'h' => 'help' @@ -105,14 +106,16 @@ $diag = $options['diag']; $drop = $options['drop']; $install = $options['install']; $buildconfig = $options['buildconfig']; +$buildconfigdist = $options['buildconfigdist']; -if ($options['help'] or (!$drop and !$install and !$buildconfig and !$diag)) { +if ($options['help'] or (!$drop and !$install and !$buildconfig and !$buildconfigdist and !$diag)) { $help = "Various PHPUnit utility functions Options: --drop Drop database and dataroot --install Install database --buildconfig Build /phpunit.xml from /phpunit.xml.dist that includes suites for all plugins and core +--buildconfigdist Build distributed phpunit.xml files for each plugin and subsystem --diag Diagnose installation and return error code only --run Execute PHPUnit tests (alternative for standard phpunit binary) @@ -136,7 +139,14 @@ if ($diag) { if (phpunit_util::build_config_file()) { exit(0); } else { - phpunit_bootstrap_error(PHPUNIT_EXITCODE_CONFIGWARNING, 'Can not create phpunit.xml configuration file, verify dirroot permissions'); + phpunit_bootstrap_error(PHPUNIT_EXITCODE_CONFIGWARNING, 'Can not create main phpunit.xml configuration file, verify dirroot permissions'); + } + +} else if ($buildconfigdist) { + if (phpunit_util::build_distributed_config_files()) { + exit(0); + } else { + phpunit_bootstrap_error(PHPUNIT_EXITCODE_CONFIGWARNING, 'Can not create main phpunit.xml configuration file, verify dirroot permissions'); } } else if ($drop) { diff --git a/lib/phpunit/lib.php b/lib/phpunit/lib.php index 40de0f01546..a0fd0a4402b 100644 --- a/lib/phpunit/lib.php +++ b/lib/phpunit/lib.php @@ -886,6 +886,170 @@ class phpunit_util { return (bool)$result; } + + /** + * Builds distributed phpunit.xml and dataroot/phpunit/webrunner.xml files using defaults from /phpunit.xml.dist + * + * @static + * @return bool true means all config files created, false means only dataroot file created + */ + public static function build_distributed_config_files() { + global $CFG; + + $template = ' + + + @dir@ + + '; + + // Use the upstream file as source for the distributed configurations + $ftemplate = file_get_contents("$CFG->dirroot/phpunit.xml.dist"); + $ftemplate = preg_replace('|lib/phpunit/bootstrap.php|', $CFG->dirroot . '/lib/phpunit/bootstrap.php', $ftemplate); + $ftemplate = preg_replace('|', $ftemplate); + + // Get all the components + $components = self::get_all_plugins_with_tests() + self::get_all_subsystems_with_tests(); + + // Get all the directories having tests + $directories = self::get_all_directories_with_tests(); + + // Find any directory not covered by proper components + $remaining = array_diff($directories, $components); + + // Add them to the list of components + $components += $remaining; + + // Create the corresponding phpunit.xml file for each component + foreach ($components as $cname => $cpath) { + // Calculate the component suite + $ctemplate = $template; + $ctemplate = str_replace('@component@', $cname, $ctemplate); + $ctemplate = str_replace('@dir@', $cpath, $ctemplate); + + // Apply it to the file template + $fcontents = str_replace('', $ctemplate, $ftemplate); + + // Write the file + $result = false; + if (is_writable($cpath)) { + if ($result = (bool)file_put_contents("$cpath/phpunit.xml", $fcontents)) { + phpunit_boostrap_fix_file_permissions("$cpath/phpunit.xml"); + } + } + // Problems writing file, throw error + if (!$result) { + phpunit_bootstrap_error(PHPUNIT_EXITCODE_CONFIGWARNING, "Can not create $cpath/phpunit.xml configuration file, verify dir permissions"); + } + } + + // Finally, build the main config file too + return self::build_config_file(); + } + + /** + * Returns all the plugins having phpunit tests + * + * @return array all the plugins having phpunit tests + * + */ + private static function get_all_plugins_with_tests() { + $pluginswithtests = array(); + + $plugintypes = get_plugin_types(); + ksort($plugintypes); + foreach ($plugintypes as $type => $unused) { + $plugs = get_plugin_list($type); + ksort($plugs); + foreach ($plugs as $plug => $fullplug) { + // Look for tests recursively + if (self::directory_has_tests($fullplug)) { + $pluginswithtests[$type . '_' . $plug] = $fullplug; + } + } + } + return $pluginswithtests; + } + + /** + * Returns all the subsystems having phpunit tests + * + * Note we are hacking here the list of subsystems + * to cover some well-known subsystems that are not properly + * returned by the {@link get_core_subsystems()} function. + * + * @return array all the subsystems having phpunit tests + */ + private static function get_all_subsystems_with_tests() { + global $CFG; + + $subsystemswithtests = array(); + + $subsystems = get_core_subsystems(); + + // Hack the list a bit to cover some well-known ones + $subsystems['backup'] = 'backup'; + $subsystems['db-dml'] = 'lib/dml'; + $subsystems['db-ddl'] = 'lib/ddl'; + + ksort($subsystems); + foreach ($subsystems as $subsys => $relsubsys) { + if ($relsubsys === null) { + continue; + } + $fullsubsys = $CFG->dirroot . '/' . $relsubsys; + if (!is_dir($fullsubsys)) { + continue; + } + // Look for tests recursively + if (self::directory_has_tests($fullsubsys)) { + $subsystemswithtests['core_' . $subsys] = $fullsubsys; + } + } + return $subsystemswithtests; + } + + /** + * Returns all the directories having tests + * + * @return array all directories having tests + */ + private static function get_all_directories_with_tests() { + global $CFG; + + $dirs = array(); + $dirite = new RecursiveDirectoryIterator($CFG->dirroot); + $iteite = new RecursiveIteratorIterator($dirite); + $regite = new RegexIterator($iteite, '|/tests/.*_test\.php$|'); + foreach ($regite as $path => $element) { + $key = dirname(dirname($path)); + $value = trim(str_replace('/', '_', str_replace($CFG->dirroot, '', $key)), '_'); + $dirs[$key] = $value; + } + ksort($dirs); + return array_flip($dirs); + } + + /** + * Returns if a given directory has tests (recursively) + * + * @param $dir string full path to the directory to look for phpunit tests + * @return bool if a given directory has tests (true) or no (false) + */ + private static function directory_has_tests($dir) { + if (!is_dir($dir)) { + return false; + } + + $dirite = new RecursiveDirectoryIterator($dir); + $iteite = new RecursiveIteratorIterator($dirite); + $regite = new RegexIterator($iteite, '|/tests/.*_test\.php$|'); + $regite->rewind(); + if ($regite->valid()) { + return true; + } + return false; + } } From 8e5c963e6b511feb87e3c21d7eeb096a1ae28206 Mon Sep 17 00:00:00 2001 From: Petr Skoda Date: Mon, 23 Apr 2012 13:51:54 +0200 Subject: [PATCH 2/2] MDL-32587 improve component phpunit config building and make the util.php help fit 80char screens --- .gitignore | 2 +- admin/tool/phpunit/cli/util.php | 46 ++++++++++++++++----------------- lib/phpunit/lib.php | 26 +++++++++---------- 3 files changed, 36 insertions(+), 38 deletions(-) diff --git a/.gitignore b/.gitignore index a57c23f7201..e95a47a4fc6 100644 --- a/.gitignore +++ b/.gitignore @@ -25,4 +25,4 @@ CVS /.project /.buildpath /.cache -/phpunit.xml \ No newline at end of file +phpunit.xml \ No newline at end of file diff --git a/admin/tool/phpunit/cli/util.php b/admin/tool/phpunit/cli/util.php index 137e9183a23..1a8cea7ab44 100644 --- a/admin/tool/phpunit/cli/util.php +++ b/admin/tool/phpunit/cli/util.php @@ -34,14 +34,14 @@ require_once(__DIR__.'/../../../../lib/phpunit/bootstraplib.php'); // now get cli options list($options, $unrecognized) = cli_get_params( array( - 'drop' => false, - 'install' => false, - 'buildconfig' => false, - 'buildconfigdist' => false, - 'diag' => false, - 'phpunitdir' => false, - 'run' => false, - 'help' => false, + 'drop' => false, + 'install' => false, + 'buildconfig' => false, + 'buildcomponentconfigs' => false, + 'diag' => false, + 'phpunitdir' => false, + 'run' => false, + 'help' => false, ), array( 'h' => 'help' @@ -106,20 +106,21 @@ $diag = $options['diag']; $drop = $options['drop']; $install = $options['install']; $buildconfig = $options['buildconfig']; -$buildconfigdist = $options['buildconfigdist']; +$buildcomponentconfigs = $options['buildcomponentconfigs']; -if ($options['help'] or (!$drop and !$install and !$buildconfig and !$buildconfigdist and !$diag)) { +if ($options['help'] or (!$drop and !$install and !$buildconfig and !$buildcomponentconfigs and !$diag)) { $help = "Various PHPUnit utility functions Options: ---drop Drop database and dataroot ---install Install database ---buildconfig Build /phpunit.xml from /phpunit.xml.dist that includes suites for all plugins and core ---buildconfigdist Build distributed phpunit.xml files for each plugin and subsystem ---diag Diagnose installation and return error code only ---run Execute PHPUnit tests (alternative for standard phpunit binary) +--drop Drop database and dataroot +--install Install database +--diag Diagnose installation and return error code only +--run Execute PHPUnit tests (alternative for standard phpunit binary) +--buildconfig Build /phpunit.xml from /phpunit.xml.dist that runs all tests +--buildcomponentconfigs + Build distributed phpunit.xml files for each component --h, --help Print out this help +-h, --help Print out this help Example: \$/usr/bin/php lib/phpunit/tool.php --install @@ -139,15 +140,12 @@ if ($diag) { if (phpunit_util::build_config_file()) { exit(0); } else { - phpunit_bootstrap_error(PHPUNIT_EXITCODE_CONFIGWARNING, 'Can not create main phpunit.xml configuration file, verify dirroot permissions'); + phpunit_bootstrap_error(PHPUNIT_EXITCODE_CONFIGWARNING, 'Can not create main /phpunit.xml configuration file, verify dirroot permissions'); } -} else if ($buildconfigdist) { - if (phpunit_util::build_distributed_config_files()) { - exit(0); - } else { - phpunit_bootstrap_error(PHPUNIT_EXITCODE_CONFIGWARNING, 'Can not create main phpunit.xml configuration file, verify dirroot permissions'); - } +} else if ($buildcomponentconfigs) { + phpunit_util::build_component_config_files(); + exit(0); } else if ($drop) { // make sure tests do not run in parallel diff --git a/lib/phpunit/lib.php b/lib/phpunit/lib.php index a0fd0a4402b..7004abf4d6e 100644 --- a/lib/phpunit/lib.php +++ b/lib/phpunit/lib.php @@ -888,24 +888,23 @@ class phpunit_util { } /** - * Builds distributed phpunit.xml and dataroot/phpunit/webrunner.xml files using defaults from /phpunit.xml.dist + * Builds phpunit.xml files for all components using defaults from /phpunit.xml.dist * * @static - * @return bool true means all config files created, false means only dataroot file created + * @return void, stops if can not write files */ - public static function build_distributed_config_files() { + public static function build_component_config_files() { global $CFG; $template = ' - @dir@ + . '; // Use the upstream file as source for the distributed configurations $ftemplate = file_get_contents("$CFG->dirroot/phpunit.xml.dist"); - $ftemplate = preg_replace('|lib/phpunit/bootstrap.php|', $CFG->dirroot . '/lib/phpunit/bootstrap.php', $ftemplate); $ftemplate = preg_replace('|', $ftemplate); // Get all the components @@ -925,11 +924,15 @@ class phpunit_util { // Calculate the component suite $ctemplate = $template; $ctemplate = str_replace('@component@', $cname, $ctemplate); - $ctemplate = str_replace('@dir@', $cpath, $ctemplate); // Apply it to the file template $fcontents = str_replace('', $ctemplate, $ftemplate); + // fix link to schema + $level = substr_count(str_replace('\\', '/', $cpath), '/') - substr_count(str_replace('\\', '/', $CFG->dirroot), '/'); + $fcontents = str_replace('lib/phpunit/phpunit.xsd', str_repeat('../', $level).'lib/phpunit/phpunit.xsd', $fcontents); + $fcontents = str_replace('lib/phpunit/bootstrap.php', str_repeat('../', $level).'lib/phpunit/bootstrap.php', $fcontents); + // Write the file $result = false; if (is_writable($cpath)) { @@ -942,15 +945,12 @@ class phpunit_util { phpunit_bootstrap_error(PHPUNIT_EXITCODE_CONFIGWARNING, "Can not create $cpath/phpunit.xml configuration file, verify dir permissions"); } } - - // Finally, build the main config file too - return self::build_config_file(); } /** - * Returns all the plugins having phpunit tests + * Returns all the plugins having PHPUnit tests * - * @return array all the plugins having phpunit tests + * @return array all the plugins having PHPUnit tests * */ private static function get_all_plugins_with_tests() { @@ -972,13 +972,13 @@ class phpunit_util { } /** - * Returns all the subsystems having phpunit tests + * Returns all the subsystems having PHPUnit tests * * Note we are hacking here the list of subsystems * to cover some well-known subsystems that are not properly * returned by the {@link get_core_subsystems()} function. * - * @return array all the subsystems having phpunit tests + * @return array all the subsystems having PHPUnit tests */ private static function get_all_subsystems_with_tests() { global $CFG;