. /** * Behat command utils * * @package core * @category test * @copyright 2012 David MonllaĆ³ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ defined('MOODLE_INTERNAL') || die(); require_once(__DIR__ . '/../lib.php'); /** * Behat command related utils * * @package core * @category test * @copyright 2013 David MonllaĆ³ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ class behat_command { /** * Docs url */ const DOCS_URL = 'https://docs.moodle.org/dev/Running_acceptance_test'; /** * Ensures the behat dir exists in moodledata * * @return string Full path */ public static function get_parent_behat_dir() { global $CFG; // If not set then return empty string. if (!isset($CFG->behat_dataroot_parent)) { return ""; } return $CFG->behat_dataroot_parent; } /** * Ensures the behat dir exists in moodledata * @param int $runprocess run process for which behat dir is returned. * @return string Full path */ public static function get_behat_dir($runprocess = 0) { global $CFG; // If not set then return empty string. if (!isset($CFG->behat_dataroot)) { return ""; } // If $CFG->behat_parallel_run starts with index 0 and $runprocess for parallel run starts with 1. if (!empty($runprocess) && isset($CFG->behat_parallel_run[$runprocess - 1]['behat_dataroot'])) { $behatdir = $CFG->behat_parallel_run[$runprocess - 1]['behat_dataroot'] . '/behat';; } else { $behatdir = $CFG->behat_dataroot . '/behat'; } if (!is_dir($behatdir)) { if (!mkdir($behatdir, $CFG->directorypermissions, true)) { behat_error(BEHAT_EXITCODE_PERMISSIONS, 'Directory ' . $behatdir . ' can not be created'); } } if (!is_writable($behatdir)) { behat_error(BEHAT_EXITCODE_PERMISSIONS, 'Directory ' . $behatdir . ' is not writable'); } return $behatdir; } /** * Returns the executable path * * Allows returning a customized command for cygwin when the * command is just displayed, when using exec(), system() and * friends we stay with DIRECTORY_SEPARATOR as they use the * normal cmd.exe (in Windows). * * @param bool $custombyterm If the provided command should depend on the terminal where it runs * @param bool $parallelrun If parallel run is installed. * @param bool $absolutepath return command with absolute path. * @return string */ public final static function get_behat_command($custombyterm = false, $parallerun = false, $absolutepath = false) { $separator = DIRECTORY_SEPARATOR; $exec = 'behat'; // Cygwin uses linux-style directory separators. if ($custombyterm && testing_is_cygwin()) { $separator = '/'; // MinGW can not execute .bat scripts. if (!testing_is_mingw()) { $exec = 'behat.bat'; } } // If relative path then prefix relative path. if ($absolutepath) { $pathprefix = testing_cli_argument_path('/'); if (!empty($pathprefix)) { $pathprefix .= $separator; } } else { $pathprefix = ''; } if (!$parallerun) { $command = $pathprefix . 'vendor' . $separator . 'bin' . $separator . $exec; } else { $command = 'php ' . $pathprefix . 'admin' . $separator . 'tool' . $separator . 'behat' . $separator . 'cli' . $separator . 'run.php'; } return $command; } /** * Runs behat command with provided options * * Execution continues when the process finishes * * @param string $options Defaults to '' so tests would be executed * @return array CLI command outputs [0] => string, [1] => integer */ public final static function run($options = '') { global $CFG; $currentcwd = getcwd(); chdir($CFG->dirroot); exec(self::get_behat_command() . ' ' . $options, $output, $code); chdir($currentcwd); return array($output, $code); } /** * Checks if behat is set up and working * * Notifies failures both from CLI and web interface. * * It checks behat dependencies have been installed and runs * the behat help command to ensure it works as expected * * @return int Error code or 0 if all ok */ public static function behat_setup_problem() { global $CFG; // Moodle setting. if (!self::are_behat_dependencies_installed()) { // Returning composer error code to avoid conflicts with behat and moodle error codes. self::output_msg(get_string('errorcomposer', 'tool_behat')); return TESTING_EXITCODE_COMPOSER; } // Behat test command. list($output, $code) = self::run(' --help'); if ($code != 0) { // Returning composer error code to avoid conflicts with behat and moodle error codes. self::output_msg(get_string('errorbehatcommand', 'tool_behat', self::get_behat_command())); return TESTING_EXITCODE_COMPOSER; } // No empty values. if (empty($CFG->behat_dataroot) || empty($CFG->behat_prefix) || empty($CFG->behat_wwwroot)) { self::output_msg(get_string('errorsetconfig', 'tool_behat')); return BEHAT_EXITCODE_CONFIG; } // Not repeated values. // We only need to check this when the behat site is not running as // at this point, when it is running, all $CFG->behat_* vars have // already been copied to $CFG->dataroot, $CFG->prefix and $CFG->wwwroot. if (!defined('BEHAT_SITE_RUNNING') && ($CFG->behat_prefix == $CFG->prefix || $CFG->behat_dataroot == $CFG->dataroot || $CFG->behat_wwwroot == $CFG->wwwroot || (!empty($CFG->phpunit_prefix) && $CFG->phpunit_prefix == $CFG->behat_prefix) || (!empty($CFG->phpunit_dataroot) && $CFG->phpunit_dataroot == $CFG->behat_dataroot) )) { self::output_msg(get_string('erroruniqueconfig', 'tool_behat')); return BEHAT_EXITCODE_CONFIG; } // Checking behat dataroot existence otherwise echo about admin/tool/behat/cli/init.php. if (!empty($CFG->behat_dataroot)) { $CFG->behat_dataroot = realpath($CFG->behat_dataroot); } if (empty($CFG->behat_dataroot) || !is_dir($CFG->behat_dataroot) || !is_writable($CFG->behat_dataroot)) { self::output_msg(get_string('errordataroot', 'tool_behat')); return BEHAT_EXITCODE_CONFIG; } // If app config is supplied, check the value is correct. if (!empty($CFG->behat_ionic_dirroot) && !file_exists($CFG->behat_ionic_dirroot . '/ionic.config.json')) { self::output_msg(get_string('errorapproot', 'tool_behat')); return BEHAT_EXITCODE_CONFIG; } return 0; } /** * Has the site installed composer. * @return bool */ public static function are_behat_dependencies_installed() { if (!is_dir(__DIR__ . '/../../../vendor/behat')) { return false; } return true; } /** * Outputs a message. * * Used in CLI + web UI methods. Stops the * execution in web. * * @param string $msg * @return void */ protected static function output_msg($msg) { global $CFG, $PAGE; // If we are using the web interface we want pretty messages. if (!CLI_SCRIPT) { $renderer = $PAGE->get_renderer('tool_behat'); echo $renderer->render_error($msg); // Stopping execution. exit(1); } else { // We continue execution after this. $clibehaterrorstr = "Ensure you set \$CFG->behat_* vars in config.php " . "and you ran admin/tool/behat/cli/init.php.\n" . "More info in " . self::DOCS_URL; echo 'Error: ' . $msg . "\n\n" . $clibehaterrorstr; } } }