MDL-37046 behat: Adding web-based tests runner
[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');
27require_once($CFG->libdir . '/phpunit/classes/util.php');
28
29class tool_behat {
30
31 /**
32 * Displays basic info about acceptance tests
33 */
34 public static function info() {
35
36 $html = tool_behat::get_info();
37 $html .= tool_behat::get_steps_definitions_form();
38 $html .= tool_behat::get_run_tests_form();
39
40 echo $html;
41 }
42
43
44 /**
45 * Lists the available steps definitions
46 */
47 public static function stepsdefinitions() {
48 global $CFG;
49
50 confirm_sesskey();
51 tool_behat::check_behat_setup();
52
53 if ($filter = optional_param('filter', false, PARAM_ALPHANUMEXT)) {
54 $filteroption = ' -d ' . $filter;
55 } else {
56 $filteroption = ' -di';
57 }
58
59 $currentcwd = getcwd();
60 chdir($CFG->behatpath);
61 exec('bin/behat' . $filteroption, $steps, $code);
62 chdir($currentcwd);
63
64 // Outputing steps.
65 $html = tool_behat::get_steps_definitions_form($filter);
66
67 $content = '';
68 if ($steps) {
69 foreach ($steps as $line) {
70
71 // Skipping the step definition context.
72 if (strpos($line, '#') == 0) {
73 $content .= htmlentities($line) . '<br/>';
74 }
75 }
76 }
77
78 if ($content === '') {
79 $content = get_string('nostepsdefinitions', 'tool_behat');
80 }
81
82 $html .= html_writer::tag('div', $content, array('id' => 'steps-definitions'));
83 echo $html;
84 }
85
86
87 /**
88 * Creates a file listing all the moodle with features and steps definitions
89 */
90 public static function buildconfigfile() {
91 // TODO
92 }
93
94 /**
95 * Runs the acceptance tests
96 */
97 public static function runtests() {
98 global $CFG;
99
100 confirm_sesskey();
101 tool_behat::check_behat_setup();
102
103 @set_time_limit(0);
104
105 $tagsoption = '';
106 if ($tags = optional_param('tags', false, PARAM_ALPHANUMEXT)) {
107 $tagsoption = ' --tags ' . $tags;
108 }
109
110 // Switching database and dataroot to test environment.
111 tool_behat::enable_test_environment();
112 $currentcwd = getcwd();
113
114 // Outputting runner form and tests results.
115 echo tool_behat::get_run_tests_form($tags);
116
117 chdir($CFG->behatpath);
118 passthru('bin/behat --format html' . $tagsoption, $code);
119
120 // Switching back to regular environment
121 tool_behat::disable_test_environment();
122 chdir($currentcwd);
123 }
124
125
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;
132
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);
138
139 // If something is not ready stop execution and display the CLI command output.
140 if ($code != 0) {
141 notice(implode(' ', $output));
142 }
143 }
144
145 /**
146 * Checks the behat setup
147 */
148 private static function check_behat_setup() {
149 global $CFG;
150
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';
155
156 if (!CLI_SCRIPT) {
157 $msg .= ' ' . html_writer::tag('a', get_string('systempaths', 'admin'), array('href' => $url));
158 }
159 notice($msg);
160 }
161
162 // Behat test command.
163 $currentcwd = getcwd();
164 chdir($CFG->behatpath);
165 exec('bin/behat --help', $output, $code);
166 chdir($currentcwd);
167
168 if ($code != 0) {
169 notice(get_string('wrongbehatsetup', 'tool_behat'));
170 }
171 }
172
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;
183
184 confirm_sesskey();
185
186 if (tool_behat::is_test_environment_enabled()) {
187 debugging('Test environment was already enabled');
188 return;
189 }
190
191 // Check that PHPUnit test environment is correctly set up.
192 tool_behat::test_environment_problem();
193
194 $behatdir = $CFG->dataroot . '/behat';
195
196 if (!is_dir($behatdir)) {
197 if (!mkdir($behatdir, $CFG->directorypermissions, true)) {
198 throw new file_exception('storedfilecannotcreatefiledirs');
199 }
200 }
201
202 if (!is_writable($behatdir)) {
203 throw new file_exception('storedfilecannotcreatefiledirs');
204 }
205
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 }
211
212 }
213
214 /**
215 * Disables test mode
216 */
217 public static function disable_test_environment() {
218 global $CFG;
219
220 confirm_sesskey();
221
222 $testenvfile = $CFG->dataroot . '/behat/test_environment_enabled.txt';
223
224 if (!tool_behat::is_test_environment_enabled()) {
225 debugging('Test environment was already disabled');
226 } else {
227 unlink($testenvfile);
228 }
229 }
230
231 /**
232 * Checks whether test environment is enabled or disabled
233 */
234 public static function is_test_environment_enabled() {
235 global $CFG;
236
237 $testenvfile = $CFG->dataroot . '/behat/test_environment_enabled.txt';
238 if (file_exists($testenvfile)) {
239 return true;
240 }
241
242 return false;
243 }
244
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;
254
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);
259
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();
267
268 return $html;
269 }
270
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;
278
279 if ($filter === false) {
280 $filter = '';
281 } else {
282 $filter = s($filter);
283 }
284
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();
298
299 return $html;
300 }
301
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;
309
310 if ($tags === false) {
311 $tags = '';
312 } else {
313 $tags = s($tags);
314 }
315
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();
329
330 return $html;
331 }
332
333}