MDL-37046 behat: Adding CLI options
[moodle.git] / admin / tool / behat / locallib.php
CommitLineData
7f541ea3
DM
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/>.
16
17/**
18 * Behat commands
19 *
20 * @package tool_behat
21 * @copyright 2012 David MonllaĆ³
22 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
23 */
24
25require_once($CFG->libdir . '/filestorage/file_exceptions.php');
26require_once($CFG->libdir . '/phpunit/bootstraplib.php');
33005f68 27require_once($CFG->libdir . '/phpunit/classes/tests_finder.php');
7f541ea3 28
6d994c51
DM
29/**
30 * Behat commands manager
31 *
32 * CLI + web execution
33 *
34 * @package tool_behat
35 * @copyright 2012 David MonllaĆ³
36 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
37 */
7f541ea3
DM
38class tool_behat {
39
40 /**
41 * Displays basic info about acceptance tests
42 */
43 public static function info() {
44
33005f68
DM
45 $html = self::get_header();
46 $html .= self::get_info();
47 $html .= self::get_build_config_file_form();
48 $html .= self::get_switch_environment_form();
49 $html .= self::get_steps_definitions_form();
50 $html .= self::get_run_tests_form();
51 $html .= self::get_footer();
7f541ea3
DM
52
53 echo $html;
54 }
55
7f541ea3
DM
56 /**
57 * Lists the available steps definitions
6d994c51 58 * @param string $filter Keyword to filter the list of steps definitions availables
7f541ea3 59 */
6d994c51 60 public static function stepsdefinitions($filter = false) {
7f541ea3
DM
61 global $CFG;
62
33005f68
DM
63 if (!CLI_SCRIPT) {
64 confirm_sesskey();
65 }
66 self::check_behat_setup();
7f541ea3 67
6d994c51
DM
68 // Priority to the one specified as argument.
69 if (!$filter) {
70 $filter = optional_param('filter', false, PARAM_ALPHANUMEXT);
71 }
72
73 if ($filter) {
7f541ea3
DM
74 $filteroption = ' -d ' . $filter;
75 } else {
76 $filteroption = ' -di';
77 }
78
79 $currentcwd = getcwd();
80 chdir($CFG->behatpath);
81 exec('bin/behat' . $filteroption, $steps, $code);
82 chdir($currentcwd);
83
84 // Outputing steps.
33005f68
DM
85 $html = self::get_header();
86 $html .= self::get_steps_definitions_form($filter);
7f541ea3
DM
87
88 $content = '';
89 if ($steps) {
90 foreach ($steps as $line) {
91
92 // Skipping the step definition context.
93 if (strpos($line, '#') == 0) {
94 $content .= htmlentities($line) . '<br/>';
95 }
96 }
97 }
98
99 if ($content === '') {
100 $content = get_string('nostepsdefinitions', 'tool_behat');
101 }
102
103 $html .= html_writer::tag('div', $content, array('id' => 'steps-definitions'));
33005f68 104 $html .= self::get_footer();
cc544646 105
7f541ea3
DM
106 echo $html;
107 }
108
cc544646
DM
109 /**
110 * Switches from and to the regular environment to the testing environment
6d994c51 111 * @param string $testenvironment enable|disable
cc544646 112 */
6d994c51 113 public static function switchenvironment($testenvironment = false) {
cc544646
DM
114 global $CFG;
115
33005f68
DM
116 if (!CLI_SCRIPT) {
117 confirm_sesskey();
118 }
6d994c51
DM
119
120 // Priority to the one specified as argument.
121 if (!$testenvironment) {
122 $testenvironment = optional_param('testenvironment', 'enable', PARAM_ALPHA);
123 }
124
cc544646 125 if ($testenvironment == 'enable') {
33005f68 126 self::enable_test_environment();
cc544646 127 } else if ($testenvironment == 'disable') {
33005f68 128 self::disable_test_environment();
cc544646
DM
129 }
130
131 redirect(get_login_url());
132 }
7f541ea3
DM
133
134 /**
135 * Creates a file listing all the moodle with features and steps definitions
136 */
137 public static function buildconfigfile() {
33005f68
DM
138 global $CFG;
139
140 if (!CLI_SCRIPT) {
141 confirm_sesskey();
142 }
143
144 // Gets all the components with features
145 $components = tests_finder::get_components_with_tests('features');
146 if ($components) {
147 $contents = 'features:' . PHP_EOL;
148 foreach ($components as $componentname => $path) {
149 $contents .= ' - ' . $path . PHP_EOL;
150 }
151 }
152
153 // Gets all the components with steps definitions
7f541ea3 154 // TODO
33005f68
DM
155
156 $fullfilename = $CFG->dataroot . '/behat/config.yml';
157 if (!file_put_contents($fullfilename, $contents)) {
158 throw new file_exception('cannotcreatefile', $fullfilename);
159 }
160
161 echo self::get_header();
162 echo self::output_success(get_string('configfilesuccess', 'tool_behat'));
163 echo self::get_footer();
7f541ea3
DM
164 }
165
166 /**
167 * Runs the acceptance tests
6d994c51
DM
168 * @param string $tags Restricts the executed tests to the ones that matches the tags
169 * @param string $extra Extra CLI behat options
7f541ea3 170 */
6d994c51 171 public static function runtests($tags = false, $extra = false) {
7f541ea3
DM
172 global $CFG;
173
33005f68
DM
174 if (!CLI_SCRIPT) {
175 confirm_sesskey();
176 }
177 self::check_behat_setup();
7f541ea3 178
33005f68 179 echo self::get_header();
cc544646 180
7f541ea3
DM
181 @set_time_limit(0);
182
6d994c51
DM
183 // Priority to the one specified as argument.
184 if (!$tags) {
185 $tags = optional_param('tags', false, PARAM_ALPHANUMEXT);
186 }
187 // $extra only passed as CLI option (to simplify web runner usage).
188
7f541ea3 189 $tagsoption = '';
6d994c51 190 if ($tags) {
7f541ea3
DM
191 $tagsoption = ' --tags ' . $tags;
192 }
193
6d994c51
DM
194 if (!$extra && !CLI_SCRIPT) {
195 $extra = ' --format html';
196 } else if(!$extra && CLI_SCRIPT) {
197 $extra = '';
198 }
199
7f541ea3 200 // Switching database and dataroot to test environment.
33005f68 201 self::enable_test_environment();
7f541ea3
DM
202 $currentcwd = getcwd();
203
204 // Outputting runner form and tests results.
6d994c51
DM
205 if (!CLI_SCRIPT) {
206 echo self::get_run_tests_form($tags);
207 }
7f541ea3
DM
208
209 chdir($CFG->behatpath);
6d994c51 210 passthru('bin/behat ' . $tagsoption . ' ' .$extra, $code);
7f541ea3
DM
211
212 // Switching back to regular environment
33005f68 213 self::disable_test_environment();
7f541ea3 214 chdir($currentcwd);
cc544646 215
33005f68 216 echo self::get_footer();
7f541ea3
DM
217 }
218
219
220 /**
221 * Checks whether the test database and dataroot is ready
222 * Stops execution if something went wrong
223 */
224 private static function test_environment_problem() {
225 global $CFG;
226
227 // phpunit --diag returns nothing if the test environment is set up correctly.
228 $currentcwd = getcwd();
229 chdir($CFG->dirroot . '/' . $CFG->admin . '/tool/phpunit/cli');
230 exec("php util.php --diag", $output, $code);
231 chdir($currentcwd);
232
233 // If something is not ready stop execution and display the CLI command output.
234 if ($code != 0) {
235 notice(implode(' ', $output));
236 }
237 }
238
239 /**
240 * Checks the behat setup
241 */
242 private static function check_behat_setup() {
243 global $CFG;
244
245 // Moodle setting.
246 if (empty($CFG->behatpath)) {
247 $msg = get_string('nobehatpath', 'tool_behat');
248 $url = $CFG->wwwroot . '/' . $CFG->admin . '/settings.php?section=systempaths';
249
250 if (!CLI_SCRIPT) {
251 $msg .= ' ' . html_writer::tag('a', get_string('systempaths', 'admin'), array('href' => $url));
252 }
253 notice($msg);
254 }
255
256 // Behat test command.
257 $currentcwd = getcwd();
258 chdir($CFG->behatpath);
259 exec('bin/behat --help', $output, $code);
260 chdir($currentcwd);
261
262 if ($code != 0) {
263 notice(get_string('wrongbehatsetup', 'tool_behat'));
264 }
265 }
266
267 /**
268 * Enables test mode checking the test environment setup
269 *
cc544646 270 * Stores a file in dataroot/behat to allow Moodle switch to
7f541ea3
DM
271 * test database and dataroot before the initial set up
272 *
273 * @throws file_exception
274 */
cc544646 275 private static function enable_test_environment() {
7f541ea3
DM
276 global $CFG;
277
33005f68 278 if (self::is_test_environment_enabled()) {
7f541ea3
DM
279 debugging('Test environment was already enabled');
280 return;
281 }
282
283 // Check that PHPUnit test environment is correctly set up.
33005f68 284 self::test_environment_problem();
7f541ea3
DM
285
286 $behatdir = $CFG->dataroot . '/behat';
287
288 if (!is_dir($behatdir)) {
289 if (!mkdir($behatdir, $CFG->directorypermissions, true)) {
290 throw new file_exception('storedfilecannotcreatefiledirs');
291 }
292 }
293
294 if (!is_writable($behatdir)) {
295 throw new file_exception('storedfilecannotcreatefiledirs');
296 }
297
33005f68 298 $contents = '$CFG->phpunit_prefix and $CFG->phpunit_dataroot are currently used as $CFG->prefix and $CFG->dataroot';
7f541ea3 299 $filepath = $behatdir . '/test_environment_enabled.txt';
33005f68 300 if (!file_put_contents($filepath, $contents)) {
7f541ea3
DM
301 throw new file_exception('cannotcreatefile', $filepath);
302 }
303
304 }
305
306 /**
307 * Disables test mode
308 */
cc544646 309 private static function disable_test_environment() {
7f541ea3 310
33005f68 311 $testenvfile = self::get_test_filepath();
7f541ea3 312
33005f68 313 if (!self::is_test_environment_enabled()) {
7f541ea3
DM
314 debugging('Test environment was already disabled');
315 } else {
cc544646
DM
316 if (!unlink($testenvfile)) {
317 throw new file_exception('cannotdeletetestenvironmentfile');
318 }
7f541ea3
DM
319 }
320 }
321
322 /**
323 * Checks whether test environment is enabled or disabled
cc544646
DM
324 *
325 * It does not return if the current script is running
326 * in test environment {@see tool_behat::is_test_environment_running()}
327 *
328 * @return bool
7f541ea3
DM
329 */
330 public static function is_test_environment_enabled() {
7f541ea3 331
33005f68 332 $testenvfile = self::get_test_filepath();
7f541ea3
DM
333 if (file_exists($testenvfile)) {
334 return true;
335 }
336
337 return false;
338 }
339
cc544646
DM
340 /**
341 * Returns true if Moodle is currently running with the test database and dataroot
342 * @return bool
343 */
344 public static function is_test_environment_running() {
345 global $CFG;
346
347 if (!empty($CFG->originaldataroot)) {
348 return true;
349 }
350
351 return false;
352 }
353
354 /**
355 * Returns the path to the file which specifies if test environment is enabled
356 * @return string
357 */
358 private static function get_test_filepath() {
359 global $CFG;
360
33005f68 361 if (self::is_test_environment_running()) {
cc544646
DM
362 $testenvfile = $CFG->originaldataroot . '/behat/test_environment_enabled.txt';
363 } else {
364 $testenvfile = $CFG->dataroot . '/behat/test_environment_enabled.txt';
365 }
366
367 return $testenvfile;
368 }
369
370 /**
371 * Returns header output
372 * @return string
373 */
374 private static function get_header() {
375 global $OUTPUT;
376
33005f68
DM
377 $action = optional_param('action', 'info', PARAM_ALPHAEXT);
378
cc544646 379 if (CLI_SCRIPT) {
33005f68 380 return '';
cc544646
DM
381 }
382
cc544646
DM
383 $title = get_string('pluginname', 'tool_behat') . ' - ' . get_string('command' . $action, 'tool_behat');
384 $html = $OUTPUT->header();
385 $html .= $OUTPUT->heading($title);
386
387 return $html;
388 }
389
390 /**
391 * Returns footer output
392 * @return string
393 */
394 private static function get_footer() {
395 global $OUTPUT;
396
397 if (CLI_SCRIPT) {
398 return '';
399 }
400
401 return $OUTPUT->footer();
402 }
403
33005f68
DM
404 /**
405 * Returns a message and a button to continue if web execution
406 * @param string $html
407 * @param string $url
408 * @return string
409 */
410 private static function output_success($html, $url = false) {
411 global $CFG, $OUTPUT;
412
413 if (!$url) {
414 $url = $CFG->wwwroot . '/' . $CFG->admin . '/tool/behat/index.php';
415 }
416
417 if (!CLI_SCRIPT) {
418 $html = $OUTPUT->box($html, 'generalbox', 'notice');
419 $html .= $OUTPUT->continue_button($url);
420 }
421
422 return $html;
423 }
424
7f541ea3
DM
425 /**
426 * Returns the installation instructions
427 *
428 * (hardcoded in English)
429 *
430 * @return string
431 */
432 private static function get_info() {
433 global $OUTPUT;
434
435 $html = $OUTPUT->box_start();
436 $html .= html_writer::tag('h1', 'Info');
437 $info = 'This tool makes use of the phpunit test environment, during the automatic acceptance tests execution the site uses the test database and dataroot directories so this tool IS NOT intended to be used in production sites.';
438 $html .= html_writer::tag('div', $info);
439
440 $html .= html_writer::tag('h1', 'Installation');
441 $installinstructions = '1.- Follow the PHPUnit installation instructions to set up the testing environment $CFG->wwwroot/admin/tool/phpunit/index.php<br/>';
442 $installinstructions .= '2.- Follow the moodle-acceptance-test installation instructions https://github.com/dmonllao/behat-moodle<br/>';
443 $installinstructions .= '3.- Set up the \'config_file_path\' param in /MOODLE-ACCEPTANCE-TEST/ROOT/PATH/behat.yml pointing to $CFG->dataroot/behat/config.yml (for example /YOUR/MOODLEDATA/PATH/behat/config.yml)<br/>';
444 $installinstructions .= '4.- Set up $CFG->behatpath in your config.php with the path of your moodle-acceptance-test installation (for example /MOODLE-ACCEPTANCE-TEST/ROOT/PATH)<br/>';
445 $html .= html_writer::tag('div', $installinstructions);
446 $html .= $OUTPUT->box_end();
447
448 return $html;
449 }
450
cc544646
DM
451 /**
452 * Returns a button to switch between environments
453 * @return string
454 */
455 private static function get_switch_environment_form() {
456 global $CFG, $OUTPUT;
457
33005f68 458 if (self::is_test_environment_running()) {
cc544646
DM
459 $perform = 'disable';
460 } else {
461 $perform = 'enable';
462 }
463 $params = array('action' => 'switchenvironment', 'testenvironment' => $perform, 'sesskey' => sesskey());
464 $url = new moodle_url('/' . $CFG->admin . '/tool/behat/index.php', $params);
465
466 $html = $OUTPUT->box_start();
467 $html .= '<p>' . get_string('switchenvironmentinfo', 'tool_behat') . '</p>';
468 $html .= $OUTPUT->single_button($url, get_string('switchenvironment' . $perform, 'tool_behat'));
469 $html .= $OUTPUT->box_end();
470
471 return $html;
472 }
473
33005f68
DM
474 /**
475 * Returns a button to execute the build config file form
476 * @return string
477 */
478 private static function get_build_config_file_form() {
479 global $OUTPUT, $CFG;
480
481 $params = array('action' => 'buildconfigfile', 'sesskey' => sesskey());
482 $url = new moodle_url('/' . $CFG->admin . '/tool/behat/index.php', $params);
483
484 $html = $OUTPUT->box_start();
485 $html .= '<p>' . get_string('buildconfigfileinfo', 'tool_behat') . '</p>';
486 $html .= $OUTPUT->single_button($url, get_string('commandbuildconfigfile', 'tool_behat'));
487 $html .= $OUTPUT->box_end();
488
489 return $html;
490 }
491
7f541ea3
DM
492 /**
493 * Returns the steps definitions form
494 * @param string $filter To filter the steps definitions list by keyword
495 * @return string
496 */
497 private static function get_steps_definitions_form($filter = false) {
498 global $OUTPUT;
499
500 if ($filter === false) {
501 $filter = '';
502 } else {
503 $filter = s($filter);
504 }
505
506 $html = $OUTPUT->box_start();
507 $html .= '<form method="get" action="index.php">';
7f541ea3
DM
508 $html .= '<fieldset class="invisiblefieldset">';
509 $html .= '<label for="id_filter">Steps definitions which contains</label> ';
510 $html .= '<input type="text" id="id_filter" value="' . $filter . '" name="filter"/> (all steps definitions if empty)';
33005f68 511 $html .= '<p></p>';
7f541ea3
DM
512 $html .= '<input type="submit" value="View available steps definitions" />';
513 $html .= '<input type="hidden" name="action" value="stepsdefinitions" />';
514 $html .= '<input type="hidden" name="sesskey" value="'.sesskey().'" />';
515 $html .= '</fieldset>';
516 $html .= '</form>';
517 $html .= $OUTPUT->box_end();
518
519 return $html;
520 }
521
522 /**
523 * Returns the run tests form
524 * @param string $tags To execute only the tests that matches the specified tag
525 * @return string
526 */
527 private static function get_run_tests_form($tags = false) {
528 global $OUTPUT;
529
530 if ($tags === false) {
531 $tags = '';
532 } else {
533 $tags = s($tags);
534 }
535
536 $html = $OUTPUT->box_start();
537 $html .= '<form method="get" action="index.php">';
7f541ea3
DM
538 $html .= '<fieldset class="invisiblefieldset">';
539 $html .= '<label for="id_tags">Tests tagged as</label> ';
540 $html .= '<input type="text" id="id_tags" value="' . $tags . '" name="tags"/> (all available tests if empty)';
33005f68 541 $html .= '<p></p>';
7f541ea3
DM
542 $html .= '<input type="submit" value="Run tests" />';
543 $html .= '<input type="hidden" name="action" value="runtests" />';
544 $html .= '<input type="hidden" name="sesskey" value="'.sesskey().'" />';
545 $html .= '</fieldset>';
546 $html .= '</form>';
547 $html .= $OUTPUT->box_end();
548
549 return $html;
550 }
7f541ea3 551}