MDL-37046 behat: Adding web-based tests runner
[moodle.git] / admin / tool / behat / locallib.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  * 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  */
25 require_once($CFG->libdir . '/filestorage/file_exceptions.php');
26 require_once($CFG->libdir . '/phpunit/bootstraplib.php');
27 require_once($CFG->libdir . '/phpunit/classes/util.php');
29 class tool_behat {
31     /**
32      * Displays basic info about acceptance tests
33      */
34     public static function info() {
36         $html = tool_behat::get_info();
37         $html .= tool_behat::get_steps_definitions_form();
38         $html .= tool_behat::get_run_tests_form();
40         echo $html;
41     }
44     /**
45      * Lists the available steps definitions
46      */
47     public static function stepsdefinitions() {
48         global $CFG;
50         confirm_sesskey();
51         tool_behat::check_behat_setup();
53         if ($filter = optional_param('filter', false, PARAM_ALPHANUMEXT)) {
54             $filteroption = ' -d ' . $filter;
55         } else {
56             $filteroption = ' -di';
57         }
59         $currentcwd = getcwd();
60         chdir($CFG->behatpath);
61         exec('bin/behat' . $filteroption, $steps, $code);
62         chdir($currentcwd);
64         // Outputing steps.
65         $html = tool_behat::get_steps_definitions_form($filter);
67         $content = '';
68         if ($steps) {
69             foreach ($steps as $line) {
71                 // Skipping the step definition context.
72                 if (strpos($line, '#') == 0) {
73                     $content .= htmlentities($line) . '<br/>';
74                 }
75             }
76         }
78         if ($content === '') {
79             $content = get_string('nostepsdefinitions', 'tool_behat');
80         }
82         $html .= html_writer::tag('div', $content, array('id' => 'steps-definitions'));
83         echo $html;
84     }
87     /**
88      * Creates a file listing all the moodle with features and steps definitions
89      */
90     public static function buildconfigfile() {
91         // TODO
92     }
94     /**
95      * Runs the acceptance tests
96      */
97     public static function runtests() {
98         global $CFG;
100         confirm_sesskey();
101         tool_behat::check_behat_setup();
103         @set_time_limit(0);
105         $tagsoption = '';
106         if ($tags = optional_param('tags', false, PARAM_ALPHANUMEXT)) {
107             $tagsoption = ' --tags ' . $tags;
108         }
110         // Switching database and dataroot to test environment.
111         tool_behat::enable_test_environment();
112         $currentcwd = getcwd();
114         // Outputting runner form and tests results.
115         echo tool_behat::get_run_tests_form($tags);
117         chdir($CFG->behatpath);
118         passthru('bin/behat --format html' . $tagsoption, $code);
120         // Switching back to regular environment
121         tool_behat::disable_test_environment();
122         chdir($currentcwd);
123     }
126     /**
127      * Checks whether the test database and dataroot is ready
128      * Stops execution if something went wrong
129      */
130     private static function test_environment_problem() {
131         global $CFG;
133         // phpunit --diag returns nothing if the test environment is set up correctly.
134         $currentcwd = getcwd();
135         chdir($CFG->dirroot . '/' . $CFG->admin . '/tool/phpunit/cli');
136         exec("php util.php --diag", $output, $code);
137         chdir($currentcwd);
139         // If something is not ready stop execution and display the CLI command output.
140         if ($code != 0) {
141             notice(implode(' ', $output));
142         }
143     }
145     /**
146      * Checks the behat setup
147      */
148     private static function check_behat_setup() {
149         global $CFG;
151         // Moodle setting.
152         if (empty($CFG->behatpath)) {
153             $msg = get_string('nobehatpath', 'tool_behat');
154             $url = $CFG->wwwroot . '/' . $CFG->admin . '/settings.php?section=systempaths';
156             if (!CLI_SCRIPT) {
157                 $msg .= ' ' . html_writer::tag('a', get_string('systempaths', 'admin'), array('href' => $url));
158             }
159             notice($msg);
160         }
162         // Behat test command.
163         $currentcwd = getcwd();
164         chdir($CFG->behatpath);
165         exec('bin/behat --help', $output, $code);
166         chdir($currentcwd);
168         if ($code != 0) {
169             notice(get_string('wrongbehatsetup', 'tool_behat'));
170         }
171     }
173     /**
174      * Enables test mode checking the test environment setup
175      *
176      * Stores a file in dataroot/behat to allow Moodle swap to
177      * test database and dataroot before the initial set up
178      *
179      * @throws file_exception
180      */
181     public static function enable_test_environment() {
182         global $CFG;
184         confirm_sesskey();
186         if (tool_behat::is_test_environment_enabled()) {
187             debugging('Test environment was already enabled');
188             return;
189         }
191         // Check that PHPUnit test environment is correctly set up.
192         tool_behat::test_environment_problem();
194         $behatdir = $CFG->dataroot . '/behat';
196         if (!is_dir($behatdir)) {
197             if (!mkdir($behatdir, $CFG->directorypermissions, true)) {
198                 throw new file_exception('storedfilecannotcreatefiledirs');
199             }
200         }
202         if (!is_writable($behatdir)) {
203             throw new file_exception('storedfilecannotcreatefiledirs');
204         }
206         $content = '$CFG->phpunit_prefix and $CFG->phpunit_dataroot are currently used as $CFG->prefix and $CFG->dataroot';
207         $filepath = $behatdir . '/test_environment_enabled.txt';
208         if (!file_put_contents($filepath, $content)) {
209             throw new file_exception('cannotcreatefile', $filepath);
210         }
212     }
214     /**
215      * Disables test mode
216      */
217     public static function disable_test_environment() {
218         global $CFG;
220         confirm_sesskey();
222         $testenvfile = $CFG->dataroot . '/behat/test_environment_enabled.txt';
224         if (!tool_behat::is_test_environment_enabled()) {
225             debugging('Test environment was already disabled');
226         } else {
227             unlink($testenvfile);
228         }
229     }
231     /**
232      * Checks whether test environment is enabled or disabled
233      */
234     public static function is_test_environment_enabled() {
235         global $CFG;
237         $testenvfile = $CFG->dataroot . '/behat/test_environment_enabled.txt';
238         if (file_exists($testenvfile)) {
239             return true;
240         }
242         return false;
243     }
245     /**
246      * Returns the installation instructions
247      *
248      * (hardcoded in English)
249      *
250      * @return string
251      */
252     private static function get_info() {
253         global $OUTPUT;
255         $html = $OUTPUT->box_start();
256         $html .= html_writer::tag('h1', 'Info');
257         $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.';
258         $html .= html_writer::tag('div', $info);
260         $html .= html_writer::tag('h1', 'Installation');
261         $installinstructions = '1.- Follow the PHPUnit installation instructions to set up the testing environment $CFG->wwwroot/admin/tool/phpunit/index.php<br/>';
262         $installinstructions .= '2.- Follow the moodle-acceptance-test installation instructions https://github.com/dmonllao/behat-moodle<br/>';
263         $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/>';
264         $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/>';
265         $html .= html_writer::tag('div', $installinstructions);
266         $html .= $OUTPUT->box_end();
268         return $html;
269     }
271     /**
272      * Returns the steps definitions form
273      * @param string $filter To filter the steps definitions list by keyword
274      * @return string
275      */
276     private static function get_steps_definitions_form($filter = false) {
277         global $OUTPUT;
279         if ($filter === false) {
280             $filter = '';
281         } else {
282             $filter = s($filter);
283         }
285         $html = $OUTPUT->box_start();
286         $html .= '<form method="get" action="index.php">';
287         $html .= '<p>';
288         $html .= '<fieldset class="invisiblefieldset">';
289         $html .= '<label for="id_filter">Steps definitions which contains</label> ';
290         $html .= '<input type="text" id="id_filter" value="' . $filter . '" name="filter"/> (all steps definitions if empty)';
291         $html .= '</p>';
292         $html .= '<input type="submit" value="View available steps definitions" />';
293         $html .= '<input type="hidden" name="action" value="stepsdefinitions" />';
294         $html .= '<input type="hidden" name="sesskey" value="'.sesskey().'" />';
295         $html .= '</fieldset>';
296         $html .= '</form>';
297         $html .= $OUTPUT->box_end();
299         return $html;
300     }
302     /**
303      * Returns the run tests form
304      * @param string $tags To execute only the tests that matches the specified tag
305      * @return string
306      */
307     private static function get_run_tests_form($tags = false) {
308         global $OUTPUT;
310         if ($tags === false) {
311             $tags = '';
312         } else {
313             $tags = s($tags);
314         }
316         $html = $OUTPUT->box_start();
317         $html .= '<form method="get" action="index.php">';
318         $html .= '<p>';
319         $html .= '<fieldset class="invisiblefieldset">';
320         $html .= '<label for="id_tags">Tests tagged as</label> ';
321         $html .= '<input type="text" id="id_tags" value="' . $tags . '" name="tags"/> (all available tests if empty)';
322         $html .= '</p>';
323         $html .= '<input type="submit" value="Run tests" />';
324         $html .= '<input type="hidden" name="action" value="runtests" />';
325         $html .= '<input type="hidden" name="sesskey" value="'.sesskey().'" />';
326         $html .= '</fieldset>';
327         $html .= '</form>';
328         $html .= $OUTPUT->box_end();
330         return $html;
331     }