Merge branch 'MDL-37046_master' of git://github.com/dmonllao/moodle
authorDan Poltawski <dan@moodle.com>
Tue, 29 Jan 2013 04:03:10 +0000 (12:03 +0800)
committerDan Poltawski <dan@moodle.com>
Tue, 29 Jan 2013 04:03:10 +0000 (12:03 +0800)
22 files changed:
.gitignore
admin/tool/behat/cli/util.php [new file with mode: 0644]
admin/tool/behat/index.php [new file with mode: 0644]
admin/tool/behat/lang/en/tool_behat.php [new file with mode: 0644]
admin/tool/behat/locallib.php [new file with mode: 0644]
admin/tool/behat/renderer.php [new file with mode: 0644]
admin/tool/behat/settings.php [new file with mode: 0644]
admin/tool/behat/steps_definitions_form.php [new file with mode: 0644]
admin/tool/behat/styles.css [new file with mode: 0644]
admin/tool/behat/tests/tool_behat_test.php [new file with mode: 0644]
admin/tool/behat/version.php [new file with mode: 0644]
behat.yml.dist [new file with mode: 0644]
composer.json
config-dist.php
lib/behat/classes/behat_command.php [new file with mode: 0644]
lib/behat/classes/behat_config_manager.php [new file with mode: 0644]
lib/behat/classes/util.php [new file with mode: 0644]
lib/behat/features/bootstrap/behat_init_context.php [new file with mode: 0644]
lib/behat/lib.php [new file with mode: 0644]
lib/pluginlib.php
lib/setup.php
lib/testing/classes/tests_finder.php

index e27bed2..e1cc233 100644 (file)
@@ -30,3 +30,4 @@ phpunit.xml
 composer.phar
 composer.lock
 /vendor/
+/behat.yml
diff --git a/admin/tool/behat/cli/util.php b/admin/tool/behat/cli/util.php
new file mode 100644 (file)
index 0000000..4fd147f
--- /dev/null
@@ -0,0 +1,182 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * CLI tool with utilities to manage Behat integration in Moodle
+ *
+ * All CLI utilities uses $CFG->behat_dataroot and $CFG->prefix_dataroot as
+ * $CFG->dataroot and $CFG->prefix
+ *
+ * @package    tool_behat
+ * @copyright  2012 David Monllaó
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+
+if (isset($_SERVER['REMOTE_ADDR'])) {
+    die(); // No access from web!.
+}
+
+// Basic functions.
+require_once(__DIR__ . '/../../../../lib/clilib.php');
+require_once(__DIR__ . '/../../../../lib/behat/lib.php');
+
+
+// CLI options.
+list($options, $unrecognized) = cli_get_params(
+    array(
+        'help'    => false,
+        'install' => false,
+        'drop'    => false,
+        'enable'  => false,
+        'disable' => false,
+    ),
+    array(
+        'h' => 'help'
+    )
+);
+
+
+// Checking util.php CLI script usage.
+$help = "
+Behat utilities to manage the test environment
+
+Options:
+--install  Installs the test environment for acceptance tests
+--drop     Drops the database tables and the dataroot contents
+--enable   Enables test environment and updates tests list
+--disable  Disables test environment
+
+-h, --help     Print out this help
+
+Example from Moodle root directory:
+\$ php admin/tool/behat/cli/util.php --enable
+
+More info in http://docs.moodle.org/dev/Acceptance_testing#Running_tests
+";
+
+if (!empty($options['help'])) {
+    echo $help;
+    exit(0);
+}
+
+
+// Checking $CFG->behat_* vars and values.
+define('BEHAT_UTIL', true);
+define('CLI_SCRIPT', true);
+define('ABORT_AFTER_CONFIG', true);
+define('NO_OUTPUT_BUFFERING', true);
+
+error_reporting(E_ALL | E_STRICT);
+ini_set('display_errors', '1');
+ini_set('log_errors', '1');
+
+require_once(__DIR__ . '/../../../../config.php');
+
+// CFG->behat_prefix must be set and with value different than CFG->prefix and phpunit_prefix.
+if (!isset($CFG->behat_prefix) ||
+   (isset($CFG->behat_prefix) &&
+       ($CFG->behat_prefix == $CFG->prefix ||
+       $CFG->behat_prefix == $CFG->phpunit_prefix))) {
+    behat_error(BEHAT_EXITCODE_CONFIG,
+        'Define $CFG->behat_prefix in config.php with a value different than $CFG->prefix and $CFG->phpunit_prefix');
+}
+
+// CFG->behat_dataroot must be set and with value different than CFG->dataroot and phpunit_dataroot.
+if (!isset($CFG->behat_dataroot) ||
+   (isset($CFG->behat_dataroot) &&
+       ($CFG->behat_dataroot == $CFG->dataroot ||
+       $CFG->behat_dataroot == $CFG->phpunit_dataroot))) {
+    behat_error(BEHAT_EXITCODE_CONFIG,
+        'Define $CFG->behat_dataroot in config.php with a value different than $CFG->dataroot and $CFG->phpunit_dataroot');
+}
+
+// Create behat_dataroot if it doesn't exists.
+if (!file_exists($CFG->behat_dataroot)) {
+    if (!mkdir($CFG->behat_dataroot, $CFG->directorypermissions)) {
+        behat_error(BEHAT_EXITCODE_PERMISSIONS, '$CFG->behat_dataroot directory can not be created');
+    }
+}
+if (!is_dir($CFG->behat_dataroot) || !is_writable($CFG->behat_dataroot)) {
+    behat_error(BEHAT_EXITCODE_PERMISSIONS, '$CFG->behat_dataroot directory has no permissions or is not a directory');
+}
+
+// Check that the directory does not contains other things.
+if (!file_exists("$CFG->behat_dataroot/behattestdir.txt")) {
+    if ($dh = opendir($CFG->behat_dataroot)) {
+        while (($file = readdir($dh)) !== false) {
+            if ($file === 'behat' or $file === '.' or $file === '..' or $file === '.DS_Store') {
+                continue;
+            }
+            behat_error(BEHAT_EXITCODE_CONFIG, '$CFG->behat_dataroot directory is not empty, ensure this is the directory where you want to install behat test dataroot');
+        }
+        closedir($dh);
+        unset($dh);
+        unset($file);
+    }
+
+    // Now we create dataroot directory structure for behat tests.
+    testing_initdataroot($CFG->behat_dataroot, 'behat');
+}
+
+// Overrides vars with behat-test ones.
+$vars = array('wwwroot', 'prefix', 'dataroot');
+foreach ($vars as $var) {
+    $CFG->{$var} = $CFG->{'behat_' . $var};
+}
+
+$CFG->noemailever = true;
+$CFG->passwordsaltmain = 'moodle';
+
+// Continues setup.
+define('ABORT_AFTER_CONFIG_CANCEL', true);
+require("$CFG->dirroot/lib/setup.php");
+
+require_once($CFG->libdir.'/adminlib.php');
+require_once($CFG->libdir.'/upgradelib.php');
+require_once($CFG->libdir.'/clilib.php');
+require_once($CFG->libdir.'/pluginlib.php');
+require_once($CFG->libdir.'/installlib.php');
+
+if ($unrecognized) {
+    $unrecognized = implode("\n  ", $unrecognized);
+    cli_error(get_string('cliunknowoption', 'admin', $unrecognized));
+}
+
+// Behat utilities.
+require_once($CFG->libdir . '/behat/classes/util.php');
+require_once($CFG->libdir . '/behat/classes/behat_command.php');
+
+// Run command (only one per time).
+if ($options['install']) {
+    behat_util::install_site();
+    mtrace("Acceptance tests site installed");
+} else if ($options['drop']) {
+    behat_util::drop_site();
+    mtrace("Acceptance tests site dropped");
+} else if ($options['enable']) {
+    behat_util::start_test_mode();
+    $runtestscommand = behat_command::get_behat_command() . ' --config '
+        . $CFG->behat_dataroot . DIRECTORY_SEPARATOR . 'behat' . DIRECTORY_SEPARATOR . 'behat.yml';
+    mtrace("Acceptance tests environment enabled, to run the tests use:\n " . $runtestscommand);
+} else if ($options['disable']) {
+    behat_util::stop_test_mode();
+    mtrace("Acceptance tests environment disabled");
+} else {
+    echo $help;
+}
+
+exit(0);
diff --git a/admin/tool/behat/index.php b/admin/tool/behat/index.php
new file mode 100644 (file)
index 0000000..f68ec13
--- /dev/null
@@ -0,0 +1,55 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Web interface to list and filter steps
+ *
+ * @package    tool_behat
+ * @copyright  2012 David Monllaó
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+require(__DIR__ . '/../../../config.php');
+require_once($CFG->libdir.'/adminlib.php');
+require_once($CFG->dirroot . '/' . $CFG->admin . '/tool/behat/locallib.php');
+require_once($CFG->libdir . '/behat/classes/behat_config_manager.php');
+
+$filter = optional_param('filter', '', PARAM_ALPHANUMEXT);
+$type = optional_param('type', false, PARAM_ALPHAEXT);
+$component = optional_param('component', '', PARAM_ALPHAEXT);
+
+admin_externalpage_setup('toolbehat');
+
+// Getting available steps definitions from behat.
+$steps = tool_behat::stepsdefinitions($type, $component, $filter);
+
+// Form.
+$componentswithsteps = array('' => get_string('allavailablesteps', 'tool_behat'));
+
+// Complete the components list with the moodle steps definitions.
+$components = behat_config_manager::get_components_steps_definitions();
+if ($components) {
+    foreach ($components as $component => $filepath) {
+        // TODO Use a class static attribute instead of the class name.
+        $componentswithsteps[$component] = 'Moodle ' . substr($component, 6);
+    }
+}
+$form = new steps_definitions_form(null, array('components' => $componentswithsteps));
+
+// Output contents.
+$renderer = $PAGE->get_renderer('tool_behat');
+echo $renderer->render_stepsdefinitions($steps, $form);
+
diff --git a/admin/tool/behat/lang/en/tool_behat.php b/admin/tool/behat/lang/en/tool_behat.php
new file mode 100644 (file)
index 0000000..e5693d7
--- /dev/null
@@ -0,0 +1,40 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Strings for tool_behat
+ *
+ * @package    tool_behat
+ * @copyright  2012 David Monllaó
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+$string['allavailablesteps'] = 'All the available steps definitions';
+$string['giveninfo'] = 'Given. Processes to set up the environment';
+$string['installinfo'] = 'Read {$a} for installation and tests execution info';
+$string['moreinfoin'] = 'More info in {$a}';
+$string['newstepsinfo'] = 'Read {$a} for info about how to add new steps definitions';
+$string['newtestsinfo'] = 'Read {$a} for info about how to write new tests';
+$string['nostepsdefinitions'] = 'There aren\'t steps definitions matching this filters';
+$string['pluginname'] = 'Acceptance testing';
+$string['stepsdefinitionscomponent'] = 'Area';
+$string['stepsdefinitionscontains'] = 'Contains';
+$string['stepsdefinitionsfilters'] = 'Steps definitions';
+$string['stepsdefinitionstype'] = 'Type';
+$string['theninfo'] = 'Then. Checkings to ensure the outcomes are the expected ones';
+$string['viewsteps'] = 'Filter';
+$string['wheninfo'] = 'When. Actions that provokes an event';
+$string['wrongbehatsetup'] = 'Something is wrong with the setup, ensure you ran the composer installer and vendor/bin/behat file has execution permissions';
diff --git a/admin/tool/behat/locallib.php b/admin/tool/behat/locallib.php
new file mode 100644 (file)
index 0000000..33a5fd8
--- /dev/null
@@ -0,0 +1,84 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Behat commands
+ *
+ * @package    tool_behat
+ * @copyright  2012 David Monllaó
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+global $CFG;
+require_once($CFG->libdir . '/behat/classes/behat_command.php');
+require_once($CFG->libdir . '/behat/classes/behat_config_manager.php');
+require_once($CFG->dirroot . '/' . $CFG->admin . '/tool/behat/steps_definitions_form.php');
+
+/**
+ * Behat commands manager
+ *
+ * @package    tool_behat
+ * @copyright  2012 David Monllaó
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class tool_behat {
+
+    /**
+     * Lists the available steps definitions
+     *
+     * @param string $type
+     * @param string $component
+     * @param string $filter
+     * @return string
+     */
+    public static function stepsdefinitions($type, $component, $filter) {
+
+        // We don't require the test environment to be enabled to list the steps definitions
+        // so test writers can more easily set up the environment.
+        behat_command::check_behat_setup();
+
+        // The loaded steps depends on the component specified.
+        behat_config_manager::update_config_file($component, false);
+
+        // The Moodle\BehatExtension\HelpPrinter\MoodleDefinitionsPrinter will parse this search format.
+        if ($type) {
+            $filter .= '&&' . $type;
+        }
+
+        if ($filter) {
+            $filteroption = ' -d "' . $filter . '"';
+        } else {
+            $filteroption = ' -di';
+        }
+
+        // Get steps definitions from Behat.
+        $options = ' --config="'.behat_config_manager::get_steps_list_config_filepath(). '" '.$filteroption;
+        list($steps, $code) = behat_command::run($options);
+
+        if ($steps) {
+            $stepshtml = implode('', $steps);
+        }
+
+        if (empty($stepshtml)) {
+            $stepshtml = get_string('nostepsdefinitions', 'tool_behat');
+        }
+
+        return $stepshtml;
+    }
+
+}
diff --git a/admin/tool/behat/renderer.php b/admin/tool/behat/renderer.php
new file mode 100644 (file)
index 0000000..1a70fce
--- /dev/null
@@ -0,0 +1,92 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Behat tool renderer
+ *
+ * @package    tool_behat
+ * @copyright  2012 David Monllaó
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+global $CFG;
+require_once($CFG->libdir . '/behat/classes/behat_command.php');
+
+/**
+ * Renderer for behat tool web features
+ *
+ * @package    tool_behat
+ * @copyright  2012 David Monllaó
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class tool_behat_renderer extends plugin_renderer_base {
+
+    /**
+     * Renders the list of available steps according to the submitted filters
+     *
+     * @param string     $stepsdefinitions HTML from behat with the available steps
+     * @param moodleform $form
+     * @return string HTML code
+     */
+    public function render_stepsdefinitions($stepsdefinitions, $form) {
+
+        $title = get_string('pluginname', 'tool_behat');
+
+        // Header.
+        $html = $this->output->header();
+        $html .= $this->output->heading($title);
+
+        // Info.
+        $installurl = behat_command::DOCS_URL . '#Installation';
+        $installlink = html_writer::tag('a', $installurl, array('href' => $installurl, 'target' => '_blank'));
+        $writetestsurl = behat_command::DOCS_URL . '#Writting_features';
+        $writetestslink = html_writer::tag('a', $writetestsurl, array('href' => $writetestsurl, 'target' => '_blank'));
+        $writestepsurl = behat_command::DOCS_URL . '#Adding_steps_definitions';
+        $writestepslink = html_writer::tag('a', $writestepsurl, array('href' => $writestepsurl, 'target' => '_blank'));
+        $infos = array(
+            get_string('installinfo', 'tool_behat', $installlink),
+            get_string('newtestsinfo', 'tool_behat', $writetestslink),
+            get_string('newstepsinfo', 'tool_behat', $writestepslink)
+        );
+
+        // List of steps
+        $html .= $this->output->box_start();
+        $html .= html_writer::tag('h1', 'Info');
+        $html .= html_writer::empty_tag('div');
+        $html .= html_writer::empty_tag('ul');
+        $html .= html_writer::empty_tag('li');
+        $html .= implode(html_writer::end_tag('li') . html_writer::empty_tag('li'), $infos);
+        $html .= html_writer::end_tag('li');
+        $html .= html_writer::end_tag('ul');
+        $html .= html_writer::end_tag('div');
+        $html .= $this->output->box_end();
+
+        // Form.
+        ob_start();
+        $form->display();
+        $html .= ob_get_contents();
+        ob_end_clean();
+
+        // Steps definitions.
+        $html .= html_writer::tag('div', $stepsdefinitions, array('class' => 'steps-definitions'));
+
+        $html .= $this->output->footer();
+
+        return $html;
+    }
+}
diff --git a/admin/tool/behat/settings.php b/admin/tool/behat/settings.php
new file mode 100644 (file)
index 0000000..7f4b5a0
--- /dev/null
@@ -0,0 +1,31 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Adds behat tests link in admin tree
+ *
+ * @package    tool_behat
+ * @copyright  2012 David Monllaó
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+
+defined('MOODLE_INTERNAL') || die();
+
+if ($hassiteconfig) {
+    $url = $CFG->wwwroot . '/' . $CFG->admin . '/tool/behat/index.php';
+    $ADMIN->add('development', new admin_externalpage('toolbehat', get_string('pluginname', 'tool_behat'), $url));
+}
diff --git a/admin/tool/behat/steps_definitions_form.php b/admin/tool/behat/steps_definitions_form.php
new file mode 100644 (file)
index 0000000..c6b06f3
--- /dev/null
@@ -0,0 +1,67 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Steps definitions form
+ *
+ * @package    tool_behat
+ * @copyright  2012 David Monllaó
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+require_once($CFG->libdir.'/formslib.php');
+
+/**
+ * Form to display the available steps definitions
+ *
+ * @package    tool_behat
+ * @copyright  2012 David Monllaó
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class steps_definitions_form extends moodleform {
+
+    /**
+     * Form definition
+     * @return void
+     */
+    public function definition() {
+
+        $mform = $this->_form;
+
+        $mform->addElement('header', 'filters', get_string('stepsdefinitionsfilters', 'tool_behat'));
+
+        $types = array(
+            '' => get_string('allavailablesteps', 'tool_behat'),
+            'given' => get_string('giveninfo', 'tool_behat'),
+            'when' => get_string('wheninfo', 'tool_behat'),
+            'then' => get_string('theninfo', 'tool_behat')
+        );
+        $mform->addElement('select', 'type', get_string('stepsdefinitionstype', 'tool_behat'), $types);
+
+        $mform->addElement(
+            'select',
+            'component',
+            get_string('stepsdefinitionscomponent', 'tool_behat'),
+            $this->_customdata['components']
+        );
+
+        $mform->addElement('text', 'filter', get_string('stepsdefinitionscontains', 'tool_behat'));
+
+        $mform->addElement('submit', 'submit', get_string('viewsteps', 'tool_behat'));
+    }
+}
diff --git a/admin/tool/behat/styles.css b/admin/tool/behat/styles.css
new file mode 100644 (file)
index 0000000..d7ca4d1
--- /dev/null
@@ -0,0 +1,5 @@
+.steps-definitions{border-style:solid;border-width:1px;border-color:#BBB;padding:5px;margin:auto;width:50%;}
+.steps-definitions .step{margin: 10px 0px 10px 0px;}
+.steps-definitions .stepdescription{color:#bf8c12;}
+.steps-definitions .steptype{color:#1467a6;margin-right: 5px;}
+.steps-definitions .stepregex{color:#060;}
diff --git a/admin/tool/behat/tests/tool_behat_test.php b/admin/tool/behat/tests/tool_behat_test.php
new file mode 100644 (file)
index 0000000..12db2e0
--- /dev/null
@@ -0,0 +1,175 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Unit tests for admin/tool/behat.
+ *
+ * @package   tool_behat
+ * @copyright  2012 David Monllaó
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+global $CFG;
+require_once($CFG->dirroot . '/' . $CFG->admin .'/tool/behat/locallib.php');
+require_once($CFG->libdir . '/behat/classes/util.php');
+require_once($CFG->libdir . '/behat/classes/behat_config_manager.php');
+
+/**
+ * Allows access to internal methods without exposing them.
+ *
+ * @package    tool_behat
+ * @copyright  2012 David Monllaó
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class testable_behat_config_manager extends behat_config_manager {
+
+    /**
+     * Allow access to protected method
+     * @see parent::merge_config()
+     * @param mixed $config
+     * @param mixed $localconfig
+     * @return mixed
+     */
+    public static function merge_config($config, $localconfig) {
+        return parent::merge_config($config, $localconfig);
+    }
+
+    /**
+     * Allow access to protected method
+     * @see parent::get_config_file_contents()
+     * @param string $prefix
+     * @param array $features
+     * @param array $stepsdefinitions
+     * @return string
+     */
+    public static function get_config_file_contents($features, $stepsdefinitions) {
+        return parent::get_config_file_contents($features, $stepsdefinitions);
+    }
+}
+
+/**
+ * Tool behat tests.
+ *
+ * @package    tool_behat
+ * @copyright  2012 David Monllaó
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class tool_behat_testcase extends advanced_testcase {
+
+    /**
+     * behat_config_manager tests.
+     */
+    public function test_merge_configs() {
+
+        // Simple default config.
+        $array1 = array(
+            'the' => 'same',
+            'simple' => 'value',
+            'array' => array(
+                'one' => 'arrayvalue1',
+                'two' => 'arrayvalue2'
+            )
+        );
+
+        // Simple override.
+        $array2 = array(
+            'simple' => 'OVERRIDDEN1',
+            'array' => array(
+                'one' => 'OVERRIDDEN2'
+            ),
+            'newprofile' => array(
+                'anotherlevel' => array(
+                    'andanotherone' => array(
+                        'list1',
+                        'list2'
+                    )
+                )
+            )
+        );
+
+        $array = testable_behat_config_manager::merge_config($array1, $array2);
+
+        // Overriddes are applied.
+        $this->assertEquals('OVERRIDDEN1', $array['simple']);
+        $this->assertEquals('OVERRIDDEN2', $array['array']['one']);
+
+        // Other values are respected.
+        $this->assertNotEmpty($array['array']['two']);
+
+        // Completely new nodes are added.
+        $this->assertNotEmpty($array['newprofile']);
+        $this->assertNotEmpty($array['newprofile']['anotherlevel']['andanotherone']);
+        $this->assertEquals('list1', $array['newprofile']['anotherlevel']['andanotherone'][0]);
+        $this->assertEquals('list2', $array['newprofile']['anotherlevel']['andanotherone'][1]);
+
+        // Complex override changing vectors to scalars and scalars to vectors.
+        $array2 = array(
+            'simple' => array(
+                'simple' => 'should',
+                'be' => 'overridden',
+                'by' => 'this-array'
+            ),
+            'array' => 'one'
+        );
+
+        $array = testable_behat_config_manager::merge_config($array1, $array2);
+
+        // Overrides applied.
+        $this->assertNotEmpty($array['simple']);
+        $this->assertNotEmpty($array['array']);
+        $this->assertTrue(is_array($array['simple']));
+        $this->assertFalse(is_array($array['array']));
+
+        // Other values are maintained.
+        $this->assertEquals('same', $array['the']);
+    }
+
+    /**
+     * behat_config_manager tests.
+     */
+    public function test_config_file_contents() {
+        global $CFG;
+
+        // To avoid user value at config.php level.
+        unset($CFG->behat_config);
+
+        // List.
+        $features = array(
+            'feature1',
+            'feature2',
+            'feature3'
+        );
+
+        // Associative array.
+        $stepsdefinitions = array(
+            'micarro' => '/me/lo/robaron',
+            'anoche' => '/cuando/yo/dormia'
+        );
+
+        $contents = testable_behat_config_manager::get_config_file_contents($features, $stepsdefinitions);
+
+        $this->assertContains('features: ' . $CFG->dirroot . '/lib/behat/features', $contents);
+        $this->assertContains('micarro: /me/lo/robaron', $contents);
+        $this->assertContains('base_url: \'' . $CFG->behat_wwwroot . '\'', $contents);
+        $this->assertContains('class: behat_init_context', $contents);
+        $this->assertContains('- feature1', $contents);
+        $this->assertContains('- feature3', $contents);
+    }
+
+}
+
diff --git a/admin/tool/behat/version.php b/admin/tool/behat/version.php
new file mode 100644 (file)
index 0000000..a5ddb15
--- /dev/null
@@ -0,0 +1,29 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * tool_behat version info
+ *
+ * @package    tool_behat
+ * @copyright  2012 David Monllaó
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+$plugin->version   = 2012120700;
+$plugin->requires  = 2012120300; // Requires Moodle 2.5.
+$plugin->component = 'tool_behat';
diff --git a/behat.yml.dist b/behat.yml.dist
new file mode 100644 (file)
index 0000000..60cf807
--- /dev/null
@@ -0,0 +1,14 @@
+default:
+  paths:
+    features: lib/behat/features
+    bootstrap: lib/behat/features/bootstrap
+  context:
+    class: behat_init_context
+  extensions:
+    Behat\MinkExtension\Extension:
+      base_url: 'http://localhost:8000'
+      goutte: null
+      selenium2: null
+    Moodle\BehatExtension\Extension:
+      features: {  }
+      steps_definitions: {  }
index 5f618de..e5d73be 100644 (file)
@@ -1,6 +1,13 @@
 {
+    "repositories" : [
+        {
+            "type": "vcs",
+            "url": "https://github.com/moodlehq/moodle-behat-extension"
+        }
+    ],
     "require-dev": {
         "phpunit/phpunit": "3.7.*",
-        "phpunit/dbUnit": "1.2.*"
+        "phpunit/dbUnit": "1.2.*",
+        "moodlehq/behat-extension": "1.0.3"
     }
-}
\ No newline at end of file
+}
index cb1aa0d..3cd7b3e 100644 (file)
@@ -536,11 +536,48 @@ $CFG->admin = 'admin';
 //                                        'otherplugin' => array('mysetting' => 'myvalue', 'thesetting' => 'thevalue'));
 //
 //=========================================================================
-// 9. PHPUNIT SUPPORT
+// 10. PHPUNIT SUPPORT
 //=========================================================================
 // $CFG->phpunit_prefix = 'phpu_';
 // $CFG->phpunit_dataroot = '/home/example/phpu_moodledata';
 // $CFG->phpunit_directorypermissions = 02777; // optional
+//
+//=========================================================================
+// 11. BEHAT SUPPORT
+//=========================================================================
+// Behat uses http://localhost:8000 as default URL to run
+// the acceptance tests, you can override this value.
+// Example:
+//   $CFG->behat_wwwroot = 'http://192.168.1.250:8000';
+//
+// You can override default Moodle configuration for Behat and add your own
+// params; here you can add more profiles, use different Mink drivers than Selenium...
+// These params would be merged with the default Moodle behat.yml, giving priority
+// to the ones specified here. The array format is YAML, following the Behat
+// params hierarchy. More info: http://docs.behat.org/guides/7.config.html
+// Example:
+//   $CFG->behat_config = array(
+//       'default' => array(
+//           'formatter' => array(
+//               'name' => 'pretty',
+//               'parameters' => array(
+//                   'decorated' => true,
+//                   'verbose' => false
+//               )
+//           )
+//       )
+//   );
+//
+// You can completely switch to test environment when "php admin/tool/behat/cli/util --enable",
+// this means that all the site accesses will be routed to the test environment instead of
+// the regular one, so NEVER USE THIS SETTING IN PRODUCTION SITES. This setting is useful
+// when working with cloud CI (continous integration) servers which requires public sites to run the
+// tests, or in testing/development installations when you are developing in a pre-PHP 5.4 server.
+// Note that with this setting enabled $CFG->behat_wwwroot is ignored and $CFG->behat_wwwroot
+// value will be the regular $CFG->wwwroot value.
+// Example:
+//   $CFG->behat_switchcompletely = true;
+//
 
 //=========================================================================
 // ALL DONE!  To continue installation, visit your main page with a browser
diff --git a/lib/behat/classes/behat_command.php b/lib/behat/classes/behat_command.php
new file mode 100644 (file)
index 0000000..39e8c25
--- /dev/null
@@ -0,0 +1,148 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * 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 = 'http://docs.moodle.org/dev/Acceptance_testing';
+
+    /**
+     * Ensures the behat dir exists in moodledata
+     * @return string Full path
+     */
+    public static function get_behat_dir() {
+        global $CFG;
+
+        $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
+     * @return string
+     */
+    public final static function get_behat_command() {
+        return 'vendor' . DIRECTORY_SEPARATOR . 'bin' . DIRECTORY_SEPARATOR . 'behat';
+    }
+
+    /**
+     * 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
+     *
+     * Uses notice() instead of behat_error() because is
+     * also called from web interface
+     *
+     * It checks behat dependencies have been installed and runs
+     * the behat help command to ensure it works as expected
+     *
+     * @param  bool $checkphp Extra check for the PHP version
+     * @return void
+     */
+    public static function check_behat_setup($checkphp = false) {
+        global $CFG;
+
+        // We don't check the PHP version if $CFG->behat_switchcompletely has been enabled.
+        // Here we are in CLI.
+        if (empty($CFG->behat_switchcompletely) && $checkphp && version_compare(PHP_VERSION, '5.4.0', '<')) {
+            behat_error(BEHAT_EXITCODE_REQUIREMENT, 'PHP 5.4 is required. See config-dist.php for possible alternatives');
+        }
+
+        // Moodle setting.
+        if (!self::are_behat_dependencies_installed()) {
+
+            $msg = get_string('wrongbehatsetup', 'tool_behat');
+
+            // With HTML.
+            $docslink = self::DOCS_URL . '#Installation';
+            if (!CLI_SCRIPT) {
+                $docslink = html_writer::tag('a', $docslink, array('href' => $docslink, 'target' => '_blank'));
+            }
+            $msg .= '. ' . get_string('moreinfoin', 'tool_behat', $docslink);
+            notice($msg);
+        }
+
+        // Behat test command.
+        list($output, $code) = self::run(' --help');
+
+        if ($code != 0) {
+            notice(get_string('wrongbehatsetup', 'tool_behat'));
+        }
+    }
+
+    /**
+     * Has the site installed composer with --dev option
+     * @return bool
+     */
+    public static function are_behat_dependencies_installed() {
+        if (!is_dir(__DIR__ . '/../../../vendor/behat')) {
+            return false;
+        }
+        return true;
+    }
+
+}
diff --git a/lib/behat/classes/behat_config_manager.php b/lib/behat/classes/behat_config_manager.php
new file mode 100644 (file)
index 0000000..1c45dbd
--- /dev/null
@@ -0,0 +1,272 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Utils to set Behat config
+ *
+ * @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');
+require_once(__DIR__ . '/behat_command.php');
+require_once(__DIR__ . '/../../testing/classes/tests_finder.php');
+
+/**
+ * Behat configuration manager
+ *
+ * Creates/updates Behat config files getting tests
+ * and steps from Moodle codebase
+ *
+ * @package    core
+ * @category   test
+ * @copyright  2012 David Monllaó
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class behat_config_manager {
+
+    /**
+     * Updates a config file
+     *
+     * The tests runner and the steps definitions list uses different
+     * config files to avoid problems with concurrent executions.
+     *
+     * The steps definitions list can be filtered by component so it's
+     * behat.yml is different from the $CFG->dirroot one.
+     *
+     * @param  string $component Restricts the obtained steps definitions to the specified component
+     * @param  string $testsrunner If the config file will be used to run tests
+     * @return void
+     */
+    public static function update_config_file($component = '', $testsrunner = true) {
+        global $CFG;
+
+        // Behat must have a separate behat.yml to have access to the whole set of features and steps definitions.
+        if ($testsrunner === true) {
+            $configfilepath = behat_command::get_behat_dir() . '/behat.yml';
+        } else {
+            // Alternative for steps definitions filtering, one for each user.
+            $configfilepath = self::get_steps_list_config_filepath();
+        }
+
+        // Gets all the components with features.
+        $features = array();
+        $components = tests_finder::get_components_with_tests('features');
+        if ($components) {
+            foreach ($components as $componentname => $path) {
+                $path = self::clean_path($path) . self::get_behat_tests_path();
+                if (empty($featurespaths[$path]) && file_exists($path)) {
+
+                    // Standarizes separator (some dirs. comes with OS-dependant separator).
+                    $uniquekey = str_replace('\\', '/', $path);
+                    $featurespaths[$uniquekey] = $path;
+                }
+            }
+            $features = array_values($featurespaths);
+        }
+
+        // Gets all the components with steps definitions.
+        $stepsdefinitions = array();
+        $steps = self::get_components_steps_definitions();
+        if ($steps) {
+            foreach ($steps as $key => $filepath) {
+                if ($component == '' || $component === $key) {
+                    $stepsdefinitions[$key] = $filepath;
+                }
+            }
+        }
+
+        // Behat config file specifing the main context class,
+        // the required Behat extensions and Moodle test wwwroot.
+        $contents = self::get_config_file_contents($features, $stepsdefinitions);
+
+        // Stores the file.
+        if (!file_put_contents($configfilepath, $contents)) {
+            behat_error(BEHAT_EXITCODE_PERMISSIONS, 'File ' . $configfilepath . ' can not be created');
+        }
+
+    }
+
+    /**
+     * Gets the list of Moodle steps definitions
+     *
+     * Class name as a key and the filepath as value
+     *
+     * Externalized from update_config_file() to use
+     * it from the steps definitions web interface
+     *
+     * @return array
+     */
+    public static function get_components_steps_definitions() {
+
+        $components = tests_finder::get_components_with_tests('stepsdefinitions');
+        if (!$components) {
+            return false;
+        }
+
+        $stepsdefinitions = array();
+        foreach ($components as $componentname => $componentpath) {
+            $componentpath = self::clean_path($componentpath);
+            $diriterator = new DirectoryIterator($componentpath . self::get_behat_tests_path());
+            $regite = new RegexIterator($diriterator, '|behat_.*\.php$|');
+
+            // All behat_*.php inside behat_config_manager::get_behat_tests_path() are added as steps definitions files.
+            foreach ($regite as $file) {
+                $key = $file->getBasename('.php');
+                $stepsdefinitions[$key] = $file->getPathname();
+            }
+        }
+
+        return $stepsdefinitions;
+    }
+
+    /**
+     * Returns the behat config file path used by the steps definition list
+     *
+     * Note this can only be called from web-based scripts so it will return the
+     * production dataroot not behat_dataroot. With this the steps definitions
+     * list is accessible without having to install the behat test site.
+     *
+     * @return string
+     */
+    public static function get_steps_list_config_filepath() {
+        global $USER;
+
+        $userdir = behat_command::get_behat_dir() . '/users/' . $USER->id;
+        make_writable_directory($userdir);
+
+        return $userdir . '/behat.yml';
+    }
+
+    /**
+     * Behat config file specifing the main context class,
+     * the required Behat extensions and Moodle test wwwroot.
+     *
+     * @param array $features The system feature files
+     * @param array $stepsdefinitions The system steps definitions
+     * @return string
+     */
+    protected static function get_config_file_contents($features, $stepsdefinitions) {
+        global $CFG;
+
+        // We require here when we are sure behat dependencies are available.
+        require_once($CFG->dirroot . '/vendor/autoload.php');
+
+        $basedir = $CFG->dirroot . DIRECTORY_SEPARATOR . 'lib' . DIRECTORY_SEPARATOR . 'behat';
+        $config = array(
+            'default' => array(
+                'paths' => array(
+                    'features' => $basedir . DIRECTORY_SEPARATOR . 'features',
+                    'bootstrap' => $basedir . DIRECTORY_SEPARATOR . 'features' . DIRECTORY_SEPARATOR . 'bootstrap',
+                ),
+                'context' => array(
+                    'class' => 'behat_init_context'
+                ),
+                'extensions' => array(
+                    'Behat\MinkExtension\Extension' => array(
+                        'base_url' => $CFG->behat_wwwroot,
+                        'goutte' => null,
+                        'selenium2' => null
+                    ),
+                    'Moodle\BehatExtension\Extension' => array(
+                        'features' => $features,
+                        'steps_definitions' => $stepsdefinitions
+                    )
+                )
+            )
+        );
+
+        // In case user defined overrides respect them over our default ones.
+        if (!empty($CFG->behat_config)) {
+            $config = self::merge_config($config, $CFG->behat_config);
+        }
+
+        return Symfony\Component\Yaml\Yaml::dump($config, 10, 2);
+    }
+
+    /**
+     * Overrides default config with local config values
+     *
+     * array_merge does not merge completely the array's values
+     *
+     * @param mixed $config The node of the default config
+     * @param mixed $localconfig The node of the local config
+     * @return mixed The merge result
+     */
+    protected static function merge_config($config, $localconfig) {
+
+        if (!is_array($config) && !is_array($localconfig)) {
+            return $localconfig;
+        }
+
+        // Local overrides also deeper default values.
+        if (is_array($config) && !is_array($localconfig)) {
+            return $localconfig;
+        }
+
+        foreach ($localconfig as $key => $value) {
+
+            // If defaults are not as deep as local values let locals override.
+            if (!is_array($config)) {
+                unset($config);
+            }
+
+            // Add the param if it doesn't exists or merge branches.
+            if (empty($config[$key])) {
+                $config[$key] = $value;
+            } else {
+                $config[$key] = self::merge_config($config[$key], $localconfig[$key]);
+            }
+        }
+
+        return $config;
+    }
+
+    /**
+     * Cleans the path returned by get_components_with_tests() to standarize it
+     *
+     * @see tests_finder::get_all_directories_with_tests() it returns the path including /tests/
+     * @param string $path
+     * @return string The string without the last /tests part
+     */
+    protected final static function clean_path($path) {
+
+        $path = rtrim($path, DIRECTORY_SEPARATOR);
+
+        $parttoremove = DIRECTORY_SEPARATOR . 'tests';
+
+        $substr = substr($path, strlen($path) - strlen($parttoremove));
+        if ($substr == $parttoremove) {
+            $path = substr($path, 0, strlen($path) - strlen($parttoremove));
+        }
+
+        return rtrim($path, DIRECTORY_SEPARATOR);
+    }
+
+    /**
+     * The relative path where components stores their behat tests
+     *
+     * @return string
+     */
+    protected final static function get_behat_tests_path() {
+        return DIRECTORY_SEPARATOR . 'tests' . DIRECTORY_SEPARATOR . 'behat';
+    }
+
+}
diff --git a/lib/behat/classes/util.php b/lib/behat/classes/util.php
new file mode 100644 (file)
index 0000000..5fe4aa3
--- /dev/null
@@ -0,0 +1,262 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Utils for behat-related stuff
+ *
+ * @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');
+require_once(__DIR__ . '/../../testing/classes/util.php');
+require_once(__DIR__ . '/behat_command.php');
+require_once(__DIR__ . '/behat_config_manager.php');
+
+require_once(__DIR__ . '/../../filelib.php');
+
+/**
+ * Init/reset utilities for Behat database and dataroot
+ *
+ * @package   core
+ * @category  test
+ * @copyright 2013 David Monllaó
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class behat_util extends testing_util {
+
+    /**
+     * @var array Files to skip when resetting dataroot folder
+     */
+    protected static $datarootskiponreset = array('.', '..', 'behat', 'behattestdir.txt');
+
+    /**
+     * @var array Files to skip when dropping dataroot folder
+     */
+    protected static $datarootskipondrop = array('.', '..', 'lock');
+
+    /**
+     * Installs a site using $CFG->dataroot and $CFG->prefix
+     * @throws coding_exception
+     * @return void
+     */
+    public static function install_site() {
+        global $DB;
+
+        if (!defined('BEHAT_UTIL')) {
+            throw new coding_exception('This method can be only used by Behat CLI tool');
+        }
+
+        // New dataroot.
+        self::reset_dataroot();
+
+        $options = array();
+        $options['adminuser'] = 'admin';
+        $options['adminpass'] = 'admin';
+        $options['fullname'] = 'Acceptance test site';
+
+        install_cli_database($options, false);
+
+        // Update admin user info.
+        $user = $DB->get_record('user', array('username' => 'admin'));
+        $user->email = 'moodle@moodlemoodle.com';
+        $user->firstname = 'Admin';
+        $user->lastname = 'User';
+        $user->city = 'Perth';
+        $user->country = 'AU';
+        $DB->update_record('user', $user);
+
+        // Sets maximum debug level.
+        set_config('debug', DEBUG_DEVELOPER);
+        set_config('debugdisplay', true);
+
+        // Keeps the current version of database and dataroot.
+        self::store_versions_hash();
+
+        // Stores the database contents for fast reset.
+        self::store_database_state();
+    }
+
+    /**
+     * Drops dataroot and remove test database tables
+     * @throws coding_exception
+     * @return void
+     */
+    public static function drop_site() {
+
+        if (!defined('BEHAT_UTIL')) {
+            throw new coding_exception('This method can be only used by Behat CLI tool');
+        }
+
+        self::reset_dataroot();
+        self::drop_dataroot();
+        self::drop_database(true);
+    }
+
+    /**
+     * Checks if $CFG->behat_wwwroot is available
+     *
+     * @return bool
+     */
+    public static function is_server_running() {
+        global $CFG;
+
+        $request = new curl();
+        $request->get($CFG->behat_wwwroot);
+
+        if ($request->get_errno() === 0) {
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * Checks whether the test database and dataroot is ready
+     * Stops execution if something went wrong
+     * @throws coding_exception
+     * @return void
+     */
+    protected static function test_environment_problem() {
+        global $CFG, $DB;
+
+        if (!defined('BEHAT_UTIL')) {
+            throw new coding_exception('This method can be only used by Behat CLI tool');
+        }
+
+        if (!self::is_test_site()) {
+            behat_error(1, 'This is not a behat test site!');
+        }
+
+        $tables = $DB->get_tables(false);
+        if (empty($tables)) {
+            behat_error(BEHAT_EXITCODE_INSTALL, '');
+        }
+
+        if (!self::is_test_data_updated()) {
+            behat_error(BEHAT_EXITCODE_REINSTALL, 'The test environment was initialised for a different version');
+        }
+    }
+
+    /**
+     * Enables test mode
+     *
+     * It uses CFG->behat_dataroot
+     *
+     * Starts the test mode checking the composer installation and
+     * the test environment and updating the available
+     * features and steps definitions.
+     *
+     * Stores a file in dataroot/behat to allow Moodle to switch
+     * to the test environment when using cli-server (or $CFG->behat_switchcompletely)
+     * @throws coding_exception
+     * @return void
+     */
+    public static function start_test_mode() {
+        global $CFG;
+
+        if (!defined('BEHAT_UTIL')) {
+            throw new coding_exception('This method can be only used by Behat CLI tool');
+        }
+
+        // Checks the behat set up and the PHP version.
+        behat_command::check_behat_setup(true);
+
+        // Check that test environment is correctly set up.
+        self::test_environment_problem();
+
+        // Updates all the Moodle features and steps definitions.
+        behat_config_manager::update_config_file();
+
+        if (self::is_test_mode_enabled()) {
+            return;
+        }
+
+        $contents = '$CFG->behat_wwwroot, $CFG->behat_prefix and $CFG->behat_dataroot' .
+            ' are currently used as $CFG->wwwroot, $CFG->prefix and $CFG->dataroot';
+        $filepath = self::get_test_file_path();
+        if (!file_put_contents($filepath, $contents)) {
+            behat_error(BEHAT_EXITCODE_PERMISSIONS, 'File ' . $filepath . ' can not be created');
+        }
+    }
+
+    /**
+     * Disables test mode
+     * @throws coding_exception
+     * @return void
+     */
+    public static function stop_test_mode() {
+
+        if (!defined('BEHAT_UTIL')) {
+            throw new coding_exception('This method can be only used by Behat CLI tool');
+        }
+
+        $testenvfile = self::get_test_file_path();
+
+        if (!self::is_test_mode_enabled()) {
+            echo "Test environment was already disabled\n";
+        } else {
+            if (!unlink($testenvfile)) {
+                behat_error(BEHAT_EXITCODE_PERMISSIONS, 'Can not delete test environment file');
+            }
+        }
+    }
+
+    /**
+     * Checks whether test environment is enabled or disabled
+     *
+     * To check is the current script is running in the test
+     * environment
+     *
+     * @see tool_behat::is_using_test_environment()
+     * @return bool
+     */
+    public static function is_test_mode_enabled() {
+
+        $testenvfile = self::get_test_file_path();
+        if (file_exists($testenvfile)) {
+            return true;
+        }
+
+        return false;
+    }
+
+    /**
+     * Returns true if Moodle is currently running with the test database and dataroot
+     * @return bool
+     */
+    public static function is_using_test_environment() {
+        global $CFG;
+
+        if (!empty($CFG->originaldataroot)) {
+            return true;
+        }
+
+        return false;
+    }
+
+    /**
+     * Returns the path to the file which specifies if test environment is enabled
+     * @return string
+     */
+    protected final static function get_test_file_path() {
+        return behat_command::get_behat_dir() . '/test_environment_enabled.txt';
+    }
+
+}
diff --git a/lib/behat/features/bootstrap/behat_init_context.php b/lib/behat/features/bootstrap/behat_init_context.php
new file mode 100644 (file)
index 0000000..01a0d18
--- /dev/null
@@ -0,0 +1,55 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Contexts initializer class
+ *
+ * @package    core
+ * @category   test
+ * @copyright  2012 David Monllaó
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+use Behat\Behat\Context\BehatContext,
+    Behat\MinkExtension\Context\MinkContext,
+    Moodle\BehatExtension\Context\MoodleContext;
+
+/**
+ * Loads main subcontexts
+ *
+ * Loading of moodle subcontexts is done by the Moodle extension
+ *
+ * Renamed from behat FeatureContext class according
+ * to Moodle coding styles conventions
+ *
+ * @package    core
+ * @category   test
+ * @copyright  2012 David Monllaó
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class behat_init_context extends BehatContext {
+
+    /**
+     * Initializes subcontexts
+     *
+     * @param  array $parameters context parameters (set them up through behat.yml)
+     * @return void
+     */
+    public function __construct(array $parameters) {
+        $this->useContext('moodle', new MoodleContext($parameters));
+    }
+
+}
diff --git a/lib/behat/lib.php b/lib/behat/lib.php
new file mode 100644 (file)
index 0000000..dda2deb
--- /dev/null
@@ -0,0 +1,71 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Behat basic functions
+ *
+ * It does not include MOODLE_INTERNAL because is part of the bootstrap
+ *
+ * @package    core
+ * @category   test
+ * @copyright  2012 David Monllaó
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+require_once(__DIR__ . '/../testing/lib.php');
+
+define('BEHAT_EXITCODE_CONFIG', 250);
+define('BEHAT_EXITCODE_REQUIREMENT', 251);
+define('BEHAT_EXITCODE_PERMISSIONS', 252);
+define('BEHAT_EXITCODE_REINSTALL', 253);
+define('BEHAT_EXITCODE_INSTALL', 254);
+
+/**
+ * Exits with an error code
+ *
+ * @param  mixed $errorcode
+ * @param  string $text
+ * @return void Stops execution with error code
+ */
+function behat_error($errorcode, $text = '') {
+
+    // Adding error prefixes.
+    switch ($errorcode) {
+        case BEHAT_EXITCODE_CONFIG:
+            $text = 'Behat config error: ' . $text;
+            break;
+        case BEHAT_EXITCODE_REQUIREMENT:
+            $text = 'Behat requirement not satisfied: ' . $text;
+            break;
+        case BEHAT_EXITCODE_PERMISSIONS:
+            $text = 'Behat permissions problem: ' . $text . ', check the permissions';
+            break;
+        case BEHAT_EXITCODE_REINSTALL:
+            $path = testing_cli_argument_path('/admin/tool/behat/cli/util.php');
+            $text = "Reinstall Behat: ".$text.", use:\n php ".$path." --drop \n php ".$path." --install";
+            break;
+        case BEHAT_EXITCODE_INSTALL:
+            $path = testing_cli_argument_path('/admin/tool/behat/cli/util.php');
+            $text = "Install Behat before enabling it, use:\n php ".$path." --install";
+            break;
+        default:
+            $text = 'Unknown error ' . $errorcode . ' ' . $text;
+            break;
+    }
+
+    testing_error($errorcode, $text);
+}
+
index e1971d1..57e15fb 100644 (file)
@@ -560,10 +560,10 @@ class plugin_manager {
             ),
 
             'tool' => array(
-                'assignmentupgrade', 'capability', 'customlang', 'dbtransfer', 'generator',
-                'health', 'innodb', 'langimport', 'multilangupgrade', 'phpunit', 'profiling',
-                'qeupgradehelper', 'replace', 'spamcleaner', 'timezoneimport', 'unittest',
-                'uploaduser', 'unsuproles', 'xmldb'
+                'assignmentupgrade', 'behat', 'capability', 'customlang', 'dbtransfer',
+                'generator', 'health', 'innodb', 'langimport', 'multilangupgrade', 'phpunit',
+                'profiling', 'qeupgradehelper', 'replace', 'spamcleaner', 'timezoneimport',
+                'unittest', 'uploaduser', 'unsuproles', 'xmldb'
             ),
 
             'webservice' => array(
index 8cf2753..87c2850 100644 (file)
@@ -90,6 +90,44 @@ if (!isset($CFG->wwwroot) or $CFG->wwwroot === 'http://example.com/moodle') {
     exit(1);
 }
 
+// Ignore $CFG->behat_wwwroot and use the same wwwroot.
+if (isset($CFG->behat_switchcompletely)) {
+    $CFG->behat_wwwroot = $CFG->wwwroot;
+
+} else if (!isset($CFG->behat_wwwroot)) {
+    // Default URL for acceptance testing, only accessible from localhost.
+    $CFG->behat_wwwroot = 'http://localhost:8000';
+}
+
+
+// Test environment is requested if:
+// * Behat is running (constant set hooking the behat init process before requiring config.php).
+// * If we are accessing though the built-in web server (cli-server).
+// * If $CFG->behat_switchcompletely has been set (maintains CLI scripts behaviour, which ATM is only preventive).
+// Test environment is enabled if:
+// * User has previously enabled through admin/tool/behat/cli/util.php --enable.
+// Both are required to switch to test mode
+if (isset($CFG->behat_dataroot) && isset($CFG->behat_prefix) && file_exists($CFG->behat_dataroot)) {
+
+    $CFG->behat_dataroot = realpath($CFG->behat_dataroot);
+
+    $switchcompletely = isset($CFG->behat_switchcompletely) && php_sapi_name() !== 'cli';
+    $builtinserver = php_sapi_name() === 'cli-server';
+    $behatrunning = defined('BEHAT_RUNNING');
+    $testenvironmentrequested = $switchcompletely || $builtinserver || $behatrunning;
+
+    // Only switch to test environment if it has been enabled.
+    $testenvironmentenabled = file_exists($CFG->behat_dataroot . '/behat/test_environment_enabled.txt');
+
+    if ($testenvironmentenabled && $testenvironmentrequested) {
+        $CFG->wwwroot = $CFG->behat_wwwroot;
+        $CFG->passwordsaltmain = 'moodle';
+        $CFG->originaldataroot = $CFG->dataroot;
+        $CFG->prefix = $CFG->behat_prefix;
+        $CFG->dataroot = $CFG->behat_dataroot;
+    }
+}
+
 // Define admin directory
 if (!isset($CFG->admin)) {   // Just in case it isn't defined in config.php
     $CFG->admin = 'admin';   // This is relative to the wwwroot and dirroot
index 0a89cfa..9bc6bda 100644 (file)
@@ -181,7 +181,7 @@ class tests_finder {
                 $regexp = '|'.$sep.'tests'.$sep.'behat'.$sep.'.*\.feature$|';
                 break;
             case 'stepsdefinitions':
-                $regexp = '|'.$sep.'tests'.$sep.'behat'.$sep.'.*\.php$|';
+                $regexp = '|'.$sep.'tests'.$sep.'behat'.$sep.'behat_.*\.php$|';
                 break;
         }