MDL-66568 behat: Support building of themes for behat
[moodle.git] / admin / tool / behat / cli / util_single_run.php
1 <?php
2 // This file is part of Moodle - http://moodle.org/
3 //
4 // Moodle is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation, either version 3 of the License, or
7 // (at your option) any later version.
8 //
9 // Moodle is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 // GNU General Public License for more details.
13 //
14 // You should have received a copy of the GNU General Public License
15 // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
17 /**
18  * CLI tool with utilities to manage Behat integration in Moodle
19  *
20  * All CLI utilities uses $CFG->behat_dataroot and $CFG->prefix_dataroot as
21  * $CFG->dataroot and $CFG->prefix
22  *
23  * @package    tool_behat
24  * @copyright  2012 David MonllaĆ³
25  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
26  */
29 if (isset($_SERVER['REMOTE_ADDR'])) {
30     die(); // No access from web!.
31 }
33 // Basic functions.
34 require_once(__DIR__ . '/../../../../lib/clilib.php');
35 require_once(__DIR__ . '/../../../../lib/behat/lib.php');
37 // CLI options.
38 list($options, $unrecognized) = cli_get_params(
39     array(
40         'help'        => false,
41         'install'     => false,
42         'parallel'    => 0,
43         'run'         => 0,
44         'drop'        => false,
45         'enable'      => false,
46         'disable'     => false,
47         'diag'        => false,
48         'tags'        => '',
49         'updatesteps' => false,
50         'optimize-runs' => '',
51         'add-core-features-to-theme' => false,
52     ),
53     array(
54         'h' => 'help',
55         'o' => 'optimize-runs',
56         'a' => 'add-core-features-to-theme',
57     )
58 );
60 if ($options['install'] or $options['drop']) {
61     define('CACHE_DISABLE_ALL', true);
62 }
64 // Checking util_single_run.php CLI script usage.
65 $help = "
66 Behat utilities to manage the test environment
68 Usage:
69   php util_single_run.php [--install|--drop|--enable|--disable|--diag|--updatesteps|--help]
71 Options:
72 --install        Installs the test environment for acceptance tests
73 --drop           Drops the database tables and the dataroot contents
74 --enable         Enables test environment and updates tests list
75 --disable        Disables test environment
76 --diag           Get behat test environment status code
77 --updatesteps    Update feature step file.
79 -o, --optimize-runs Split features with specified tags in all parallel runs.
80 -a, --add-core-features-to-theme Add all core features to specified theme's
82 -h, --help Print out this help
84 Example from Moodle root directory:
85 \$ php admin/tool/behat/cli/util_single_run.php --enable
87 More info in http://docs.moodle.org/dev/Acceptance_testing#Running_tests
88 ";
90 if (!empty($options['help'])) {
91     echo $help;
92     exit(0);
93 }
95 // Describe this script.
96 define('BEHAT_UTIL', true);
97 define('CLI_SCRIPT', true);
98 define('NO_OUTPUT_BUFFERING', true);
99 define('IGNORE_COMPONENT_CACHE', true);
101 // Set run value, to be used by setup for configuring proper CFG variables.
102 if ($options['run']) {
103     define('BEHAT_CURRENT_RUN', $options['run']);
106 // Only load CFG from config.php, stop ASAP in lib/setup.php.
107 define('ABORT_AFTER_CONFIG', true);
108 require_once(__DIR__ . '/../../../../config.php');
110 // Remove error handling overrides done in config.php.
111 $CFG->debug = (E_ALL | E_STRICT);
112 $CFG->debugdisplay = 1;
113 error_reporting($CFG->debug);
114 ini_set('display_errors', '1');
115 ini_set('log_errors', '1');
117 // Finish moodle init.
118 define('ABORT_AFTER_CONFIG_CANCEL', true);
119 require("$CFG->dirroot/lib/setup.php");
121 raise_memory_limit(MEMORY_HUGE);
123 require_once($CFG->libdir.'/adminlib.php');
124 require_once($CFG->libdir.'/upgradelib.php');
125 require_once($CFG->libdir.'/clilib.php');
126 require_once($CFG->libdir.'/installlib.php');
127 require_once($CFG->libdir.'/testing/classes/test_lock.php');
129 if ($unrecognized) {
130     $unrecognized = implode(PHP_EOL . "  ", $unrecognized);
131     cli_error(get_string('cliunknowoption', 'admin', $unrecognized));
134 // Behat utilities.
135 require_once($CFG->libdir . '/behat/classes/util.php');
136 require_once($CFG->libdir . '/behat/classes/behat_command.php');
137 require_once($CFG->libdir . '/behat/classes/behat_config_manager.php');
139 // Ensure run option is <= parallel run installed.
140 $run = 0;
141 $parallel = 0;
142 if ($options['run']) {
143     $run = $options['run'];
144     // If parallel option is not passed, then try get it form config.
145     if (!$options['parallel']) {
146         $parallel = behat_config_manager::get_behat_run_config_value('parallel');
147     } else {
148         $parallel = $options['parallel'];
149     }
151     if (empty($parallel) || $run > $parallel) {
152         echo "Parallel runs can't be more then ".$parallel.PHP_EOL;
153         exit(1);
154     }
155     $CFG->behatrunprocess = $run;
158 // Run command (only one per time).
159 if ($options['install']) {
160     behat_util::install_site();
162     // This is only displayed once for parallel install.
163     if (empty($run)) {
164         mtrace("Acceptance tests site installed");
165     }
167     // Note: Do not build the themes here. This is done during the 'enable' stage.
169 } else if ($options['drop']) {
170     // Ensure no tests are running.
171     test_lock::acquire('behat');
172     behat_util::drop_site();
173     // This is only displayed once for parallel install.
174     if (empty($run)) {
175         mtrace("Acceptance tests site dropped");
176     }
178 } else if ($options['enable']) {
179     if (!empty($parallel)) {
180         // Save parallel site info for enable and install options.
181         behat_config_manager::set_behat_run_config_value('behatsiteenabled', 1);
182     }
184     // Enable test mode.
185     behat_util::start_test_mode($options['add-core-features-to-theme'], $options['optimize-runs'], $parallel, $run);
187     // Themes are only built in the 'enable' command.
188     behat_util::build_themes();
189     mtrace("Testing environment themes built");
191     // This is only displayed once for parallel install.
192     if (empty($run)) {
193         // Notify user that 2.5 profile has been converted to 3.5.
194         if (behat_config_manager::$autoprofileconversion) {
195             mtrace("2.5 behat profile detected, automatically converted to current 3.x format");
196         }
198         $runtestscommand = behat_command::get_behat_command(true, !empty($run));
200         $runtestscommand .= ' --config ' . behat_config_manager::get_behat_cli_config_filepath();
201         mtrace("Acceptance tests environment enabled on $CFG->behat_wwwroot, to run the tests use: " . PHP_EOL .
202             $runtestscommand);
203     }
205 } else if ($options['disable']) {
206     behat_util::stop_test_mode($run);
207     // This is only displayed once for parallel install.
208     if (empty($run)) {
209         mtrace("Acceptance tests environment disabled");
210     }
212 } else if ($options['diag']) {
213     $code = behat_util::get_behat_status();
214     exit($code);
216 } else if ($options['updatesteps']) {
217     if (defined('BEHAT_FEATURE_STEP_FILE') && BEHAT_FEATURE_STEP_FILE) {
218         $behatstepfile = BEHAT_FEATURE_STEP_FILE;
219     } else {
220         echo "BEHAT_FEATURE_STEP_FILE is not set, please ensure you set this to writable file" . PHP_EOL;
221         exit(1);
222     }
224     // Run behat command to get steps in feature files.
225     $featurestepscmd = behat_command::get_behat_command(true);
226     $featurestepscmd .= ' --config ' . behat_config_manager::get_behat_cli_config_filepath();
227     $featurestepscmd .= ' --dry-run --format=moodle_stepcount';
228     $processes = cli_execute_parallel(array($featurestepscmd), __DIR__ . "/../../../../");
229     $status = print_update_step_output(array_pop($processes), $behatstepfile);
231     exit($status);
232 } else {
233     echo $help;
234     exit(1);
237 exit(0);
239 /**
240  * Print update progress as dots for updating feature file step list.
241  *
242  * @param Process $process process executing update step command.
243  * @param string $featurestepfile feature step file in which steps will be saved.
244  * @return int exitcode.
245  */
246 function print_update_step_output($process, $featurestepfile) {
247     $printedlength = 0;
249     echo "Updating steps feature file for parallel behat runs" . PHP_EOL;
251     // Show progress while running command.
252     while ($process->isRunning()) {
253         usleep(10000);
254         $op = $process->getIncrementalOutput();
255         if (trim($op)) {
256             echo ".";
257             $printedlength++;
258             if ($printedlength > 70) {
259                 $printedlength = 0;
260                 echo PHP_EOL;
261             }
262         }
263     }
265     // If any error then exit.
266     $exitcode = $process->getExitCode();
267     // Output err.
268     if ($exitcode != 0) {
269         echo $process->getErrorOutput();
270         exit($exitcode);
271     }
273     // Extract features with step info and save it in file.
274     $featuresteps = $process->getOutput();
275     $featuresteps = explode(PHP_EOL, $featuresteps);
277     $realroot = realpath(__DIR__.'/../../../../').'/';
278     foreach ($featuresteps as $featurestep) {
279         if (trim($featurestep)) {
280             $step = explode("::", $featurestep);
281             $step[0] = str_replace($realroot, '', $step[0]);
282             $steps[$step[0]] = $step[1];
283         }
284     }
286     if ($existing = @json_decode(file_get_contents($featurestepfile), true)) {
287         $steps = array_merge($existing, $steps);
288     }
289     arsort($steps);
291     if (!@file_put_contents($featurestepfile, json_encode($steps, JSON_PRETTY_PRINT))) {
292         behat_error(BEHAT_EXITCODE_PERMISSIONS, 'File ' . $featurestepfile . ' can not be created');
293         $exitcode = -1;
294     }
296     echo PHP_EOL. "Updated step count in " . $featurestepfile . PHP_EOL;
298     return $exitcode;