This commit is contained in:
David Monllao 2016-08-24 09:26:29 +08:00
commit 30daa61475
15 changed files with 1851 additions and 357 deletions

View file

@ -47,11 +47,13 @@ list($options, $unrecognized) = cli_get_params(
'help' => false, 'help' => false,
'fromrun' => 1, 'fromrun' => 1,
'torun' => 0, 'torun' => 0,
'themesuitewithallfeatures' => false,
), ),
array( array(
'j' => 'parallel', 'j' => 'parallel',
'm' => 'maxruns', 'm' => 'maxruns',
'h' => 'help', 'h' => 'help',
'a' => 'themesuitewithallfeatures',
) )
); );
@ -68,6 +70,8 @@ Options:
--fromrun Execute run starting from (Used for parallel runs on different vms) --fromrun Execute run starting from (Used for parallel runs on different vms)
--torun Execute run till (Used for parallel runs on different vms) --torun Execute run till (Used for parallel runs on different vms)
-a, --themesuitewithallfeatures Theme suite do not include core features by default. If you want to run core features
with theme, then use this option.
-h, --help Print out this help -h, --help Print out this help
Example from Moodle root directory: Example from Moodle root directory:
@ -95,6 +99,11 @@ if ($options['parallel'] && $options['parallel'] > 1) {
} }
} }
$themesuitewithallfeatures = '';
if ($options['themesuitewithallfeatures']) {
$themesuitewithallfeatures = '--themesuitewithallfeatures="true"';
}
// Changing the cwd to admin/tool/behat/cli. // Changing the cwd to admin/tool/behat/cli.
$cwd = getcwd(); $cwd = getcwd();
$output = null; $output = null;
@ -104,7 +113,7 @@ testing_update_composer_dependencies();
// Check whether the behat test environment needs to be updated. // Check whether the behat test environment needs to be updated.
chdir(__DIR__); chdir(__DIR__);
exec("php $utilfile --diag $paralleloption", $output, $code); exec("php $utilfile --diag $paralleloption $themesuitewithallfeatures", $output, $code);
if ($code == 0) { if ($code == 0) {
echo "Behat test environment already installed\n"; echo "Behat test environment already installed\n";
@ -112,7 +121,7 @@ if ($code == 0) {
} else if ($code == BEHAT_EXITCODE_INSTALL) { } else if ($code == BEHAT_EXITCODE_INSTALL) {
// Behat and dependencies are installed and we need to install the test site. // Behat and dependencies are installed and we need to install the test site.
chdir(__DIR__); chdir(__DIR__);
passthru("php $utilfile --install $paralleloption", $code); passthru("php $utilfile --install $paralleloption $themesuitewithallfeatures", $code);
if ($code != 0) { if ($code != 0) {
chdir($cwd); chdir($cwd);
exit($code); exit($code);
@ -121,14 +130,14 @@ if ($code == 0) {
} else if ($code == BEHAT_EXITCODE_REINSTALL) { } else if ($code == BEHAT_EXITCODE_REINSTALL) {
// Test site data is outdated. // Test site data is outdated.
chdir(__DIR__); chdir(__DIR__);
passthru("php $utilfile --drop $paralleloption", $code); passthru("php $utilfile --drop $paralleloption $themesuitewithallfeatures", $code);
if ($code != 0) { if ($code != 0) {
chdir($cwd); chdir($cwd);
exit($code); exit($code);
} }
chdir(__DIR__); chdir(__DIR__);
passthru("php $utilfile --install $paralleloption", $code); passthru("php $utilfile --install $paralleloption $themesuitewithallfeatures", $code);
if ($code != 0) { if ($code != 0) {
chdir($cwd); chdir($cwd);
exit($code); exit($code);
@ -143,7 +152,7 @@ if ($code == 0) {
// Enable editing mode according to config.php vars. // Enable editing mode according to config.php vars.
chdir(__DIR__); chdir(__DIR__);
passthru("php $utilfile --enable $paralleloption", $code); passthru("php $utilfile --enable $paralleloption $themesuitewithallfeatures", $code);
if ($code != 0) { if ($code != 0) {
echo "Error enabling site" . PHP_EOL; echo "Error enabling site" . PHP_EOL;
chdir($cwd); chdir($cwd);

View file

@ -51,15 +51,18 @@ list($options, $unrecognised) = cli_get_params(
'tags' => '', 'tags' => '',
'profile' => '', 'profile' => '',
'feature' => '', 'feature' => '',
'suite' => '',
'fromrun' => 1, 'fromrun' => 1,
'torun' => 0, 'torun' => 0,
'single-run' => false, 'single-run' => false,
'themesuitewithallfeatures' => false,
), ),
array( array(
'h' => 'help', 'h' => 'help',
't' => 'tags', 't' => 'tags',
'p' => 'profile', 'p' => 'profile',
's' => 'single-run', 's' => 'single-run',
'a' => 'themesuitewithallfeatures',
) )
); );
@ -73,10 +76,13 @@ Usage:
Options: Options:
--BEHAT_OPTION Any combination of behat option specified in http://behat.readthedocs.org/en/v2.5/guides/6.cli.html --BEHAT_OPTION Any combination of behat option specified in http://behat.readthedocs.org/en/v2.5/guides/6.cli.html
--feature Only execute specified feature file (Absolute path of feature file). --feature Only execute specified feature file (Absolute path of feature file).
--suite Specified theme scenarios will be executed.
--replace Replace args string with run process number, useful for output. --replace Replace args string with run process number, useful for output.
--fromrun Execute run starting from (Used for parallel runs on different vms) --fromrun Execute run starting from (Used for parallel runs on different vms)
--torun Execute run till (Used for parallel runs on different vms) --torun Execute run till (Used for parallel runs on different vms)
-a, --themesuitewithallfeatures Theme suite do not include core features by default. If you want to run core features
with theme, then use this option.
-h, --help Print out this help -h, --help Print out this help
Example from Moodle root directory: Example from Moodle root directory:
@ -101,9 +107,6 @@ if (empty($options['torun'])) {
if (extension_loaded('pcntl')) { if (extension_loaded('pcntl')) {
$disabled = explode(',', ini_get('disable_functions')); $disabled = explode(',', ini_get('disable_functions'));
if (!in_array('pcntl_signal', $disabled)) { if (!in_array('pcntl_signal', $disabled)) {
// Handle interrupts on PHP7.
declare(ticks = 1);
pcntl_signal(SIGTERM, "signal_handler"); pcntl_signal(SIGTERM, "signal_handler");
pcntl_signal(SIGINT, "signal_handler"); pcntl_signal(SIGINT, "signal_handler");
} }
@ -144,6 +147,11 @@ if ($options['tags']) {
$extraopts[] = '--tags="' . $tags . '"'; $extraopts[] = '--tags="' . $tags . '"';
} }
// Add suite option if specified.
if ($options['suite']) {
$extraopts[] = '--suite="' . $options['suite'] . '"';
}
// Feature should be added to last, for behat command. // Feature should be added to last, for behat command.
if ($options['feature']) { if ($options['feature']) {
$extraopts[] = $options['feature']; $extraopts[] = $options['feature'];
@ -170,6 +178,8 @@ if (empty($parallelrun)) {
// Update config file if tags defined. // Update config file if tags defined.
if ($tags) { if ($tags) {
define('ABORT_AFTER_CONFIG_CANCEL', true);
require("$CFG->dirroot/lib/setup.php");
// Hack to set proper dataroot and wwwroot. // Hack to set proper dataroot and wwwroot.
$behatdataroot = $CFG->behat_dataroot; $behatdataroot = $CFG->behat_dataroot;
$behatwwwroot = $CFG->behat_wwwroot; $behatwwwroot = $CFG->behat_wwwroot;
@ -186,7 +196,7 @@ if ($tags) {
} else { } else {
$CFG->behat_dataroot = $behatdataroot . $i; $CFG->behat_dataroot = $behatdataroot . $i;
} }
behat_config_manager::update_config_file('', true, $tags); behat_config_manager::update_config_file('', true, $tags, $options['themesuitewithallfeatures'], $parallelrun);
} }
$CFG->behat_dataroot = $behatdataroot; $CFG->behat_dataroot = $behatdataroot;
$CFG->behat_wwwroot = $behatwwwroot; $CFG->behat_wwwroot = $behatwwwroot;

View file

@ -56,11 +56,13 @@ list($options, $unrecognized) = cli_get_params(
'updatesteps' => false, 'updatesteps' => false,
'fromrun' => 1, 'fromrun' => 1,
'torun' => 0, 'torun' => 0,
'themesuitewithallfeatures' => false,
), ),
array( array(
'h' => 'help', 'h' => 'help',
'j' => 'parallel', 'j' => 'parallel',
'm' => 'maxruns' 'm' => 'maxruns',
'a' => 'themesuitewithallfeatures',
) )
); );
@ -78,9 +80,11 @@ Options:
--disable Disables test environment --disable Disables test environment
--diag Get behat test environment status code --diag Get behat test environment status code
--updatesteps Update feature step file. --updatesteps Update feature step file.
-j, --parallel Number of parallel behat run operation -j, --parallel Number of parallel behat run operation
-m, --maxruns Max parallel processes to be executed at one time. -m, --maxruns Max parallel processes to be executed at one time.
-a, --themesuitewithallfeatures Theme suite do not include core features by default. If you want to run core features
with theme, then use this option.
-h, --help Print out this help -h, --help Print out this help
Example from Moodle root directory: Example from Moodle root directory:
@ -175,12 +179,15 @@ if ($options['diag'] || $options['enable'] || $options['disable']) {
} else if ($options['updatesteps']) { } else if ($options['updatesteps']) {
// Rewrite config file to ensure we have all the features covered. // Rewrite config file to ensure we have all the features covered.
if (empty($options['parallel'])) { if (empty($options['parallel'])) {
behat_config_manager::update_config_file(); behat_config_manager::update_config_file('', true, '', $options['themesuitewithallfeatures'], false, false);
} else { } else {
// Update config file, ensuring we have up-to-date behat.yml. // Update config file, ensuring we have up-to-date behat.yml.
for ($i = $options['fromrun']; $i <= $options['torun']; $i++) { for ($i = $options['fromrun']; $i <= $options['torun']; $i++) {
$CFG->behatrunprocess = $i; $CFG->behatrunprocess = $i;
behat_config_manager::update_config_file();
// Update config file for each run.
behat_config_manager::update_config_file('', true, '', $options['themesuitewithallfeatures'],
$options['parallel'], $i);
} }
unset($CFG->behatrunprocess); unset($CFG->behatrunprocess);
} }

View file

@ -40,16 +40,18 @@ list($options, $unrecognized) = cli_get_params(
'help' => false, 'help' => false,
'install' => false, 'install' => false,
'parallel' => 0, 'parallel' => 0,
'run' => '', 'run' => 0,
'drop' => false, 'drop' => false,
'enable' => false, 'enable' => false,
'disable' => false, 'disable' => false,
'diag' => false, 'diag' => false,
'tags' => '', 'tags' => '',
'updatesteps' => false, 'updatesteps' => false,
'themesuitewithallfeatures' => false,
), ),
array( array(
'h' => 'help' 'h' => 'help',
'a' => 'themesuitewithallfeatures',
) )
); );
@ -72,6 +74,8 @@ Options:
--diag Get behat test environment status code --diag Get behat test environment status code
--updatesteps Update feature step file. --updatesteps Update feature step file.
-a, --themesuitewithallfeatures Theme suite do not include core features by default. If you want to run core features
with theme, then use this option.
-h, --help Print out this help -h, --help Print out this help
Example from Moodle root directory: Example from Moodle root directory:
@ -130,15 +134,22 @@ require_once($CFG->libdir . '/behat/classes/behat_command.php');
require_once($CFG->libdir . '/behat/classes/behat_config_manager.php'); require_once($CFG->libdir . '/behat/classes/behat_config_manager.php');
// Ensure run option is <= parallel run installed. // Ensure run option is <= parallel run installed.
$run = 0;
$parallel = 0;
if ($options['run']) { if ($options['run']) {
$run = $options['run'];
// If parallel option is not passed, then try get it form config.
if (!$options['parallel']) { if (!$options['parallel']) {
$options['parallel'] = behat_config_manager::get_parallel_test_runs(); $parallel = behat_config_manager::get_parallel_test_runs();
} else {
$parallel = $options['parallel'];
} }
if (empty($options['parallel']) || $options['run'] > $options['parallel']) {
echo "Parallel runs can't be more then ".$options['parallel'].PHP_EOL; if (empty($parallel) || $run > $parallel) {
echo "Parallel runs can't be more then ".$parallel.PHP_EOL;
exit(1); exit(1);
} }
$CFG->behatrunprocess = $options['run']; $CFG->behatrunprocess = $run;
} }
// Run command (only one per time). // Run command (only one per time).
@ -146,7 +157,7 @@ if ($options['install']) {
behat_util::install_site(); behat_util::install_site();
// This is only displayed once for parallel install. // This is only displayed once for parallel install.
if (empty($options['run'])) { if (empty($run)) {
mtrace("Acceptance tests site installed"); mtrace("Acceptance tests site installed");
} }
@ -155,30 +166,30 @@ if ($options['install']) {
test_lock::acquire('behat'); test_lock::acquire('behat');
behat_util::drop_site(); behat_util::drop_site();
// This is only displayed once for parallel install. // This is only displayed once for parallel install.
if (empty($options['run'])) { if (empty($run)) {
mtrace("Acceptance tests site dropped"); mtrace("Acceptance tests site dropped");
} }
} else if ($options['enable']) { } else if ($options['enable']) {
if (!empty($options['parallel'])) { if (!empty($parallel)) {
// Save parallel site info for enable and install options. // Save parallel site info for enable and install options.
$filepath = behat_config_manager::get_parallel_test_file_path(); $filepath = behat_config_manager::get_parallel_test_file_path();
if (!file_put_contents($filepath, $options['parallel'])) { if (!file_put_contents($filepath, $parallel)) {
behat_error(BEHAT_EXITCODE_PERMISSIONS, 'File ' . $filepath . ' can not be created'); behat_error(BEHAT_EXITCODE_PERMISSIONS, 'File ' . $filepath . ' can not be created');
} }
} }
// Enable test mode. // Enable test mode.
behat_util::start_test_mode(); behat_util::start_test_mode($options['themesuitewithallfeatures'], $parallel, $run);
// This is only displayed once for parallel install. // This is only displayed once for parallel install.
if (empty($options['run'])) { if (empty($run)) {
// Notify user that 2.5 profile has been converted to 3.5. // Notify user that 2.5 profile has been converted to 3.5.
if (behat_config_manager::$autoprofileconversion) { if (behat_config_manager::$autoprofileconversion) {
mtrace("2.5 behat profile detected, automatically converted to current 3.x format"); mtrace("2.5 behat profile detected, automatically converted to current 3.x format");
} }
$runtestscommand = behat_command::get_behat_command(true, !empty($options['run'])); $runtestscommand = behat_command::get_behat_command(true, !empty($run));
$runtestscommand .= ' --config ' . behat_config_manager::get_behat_cli_config_filepath(); $runtestscommand .= ' --config ' . behat_config_manager::get_behat_cli_config_filepath();
mtrace("Acceptance tests environment enabled on $CFG->behat_wwwroot, to run the tests use: " . PHP_EOL . mtrace("Acceptance tests environment enabled on $CFG->behat_wwwroot, to run the tests use: " . PHP_EOL .
@ -188,7 +199,7 @@ if ($options['install']) {
} else if ($options['disable']) { } else if ($options['disable']) {
behat_util::stop_test_mode(); behat_util::stop_test_mode();
// This is only displayed once for parallel install. // This is only displayed once for parallel install.
if (empty($options['run'])) { if (empty($run)) {
mtrace("Acceptance tests environment disabled"); mtrace("Acceptance tests environment disabled");
} }

View file

@ -45,7 +45,8 @@ $steps = tool_behat::stepsdefinitions($type, $component, $filter);
$componentswithsteps = array('' => get_string('allavailablesteps', 'tool_behat')); $componentswithsteps = array('' => get_string('allavailablesteps', 'tool_behat'));
// Complete the components list with the moodle steps definitions. // Complete the components list with the moodle steps definitions.
$components = behat_config_manager::get_components_steps_definitions(); $behatconfig = new behat_config_util();
$components = $behatconfig->get_components_contexts();
if ($components) { if ($components) {
foreach ($components as $component => $filepath) { foreach ($components as $component => $filepath) {
// TODO Use a class static attribute instead of the class name. // TODO Use a class static attribute instead of the class name.

View file

@ -70,6 +70,7 @@ class tool_behat_manager_testcase extends advanced_testcase {
); );
$array = testable_behat_config_manager::merge_config($array1, $array2); $array = testable_behat_config_manager::merge_config($array1, $array2);
$this->assertDebuggingCalled("Use of merge_config is deprecated, please see behat_config_util");
// Overrides are applied. // Overrides are applied.
$this->assertEquals('OVERRIDDEN1', $array['simple']); $this->assertEquals('OVERRIDDEN1', $array['simple']);
@ -95,6 +96,7 @@ class tool_behat_manager_testcase extends advanced_testcase {
); );
$array = testable_behat_config_manager::merge_config($array1, $array2); $array = testable_behat_config_manager::merge_config($array1, $array2);
$this->assertDebuggingCalled("Use of merge_config is deprecated, please see behat_config_util");
// Overrides applied. // Overrides applied.
$this->assertNotEmpty($array['simple']); $this->assertNotEmpty($array['simple']);
@ -138,6 +140,7 @@ class tool_behat_manager_testcase extends advanced_testcase {
); );
$contents = testable_behat_config_manager::get_config_file_contents($features, $stepsdefinitions); $contents = testable_behat_config_manager::get_config_file_contents($features, $stepsdefinitions);
$this->assertDebuggingCalled("Use of get_config_file_contents is deprecated, please see behat_config_util");
// YAML decides when is is necessary to wrap strings between single quotes, so not controlled // YAML decides when is is necessary to wrap strings between single quotes, so not controlled
// values like paths should not be asserted including the key name as they would depend on the // values like paths should not be asserted including the key name as they would depend on the

View file

@ -0,0 +1,394 @@
<?php
// @codingStandardsIgnoreFile
// @codeCoverageIgnoreStart
// 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 behat manager.
*
* @package tool_behat
* @copyright 2016 Rajesh Taneja
* @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');
/**
* Behat manager tests.
*
* @package tool_behat
* @copyright 2016 Rajesh Taneja
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class tool_behat_manager_util_testcase extends advanced_testcase {
/**
* @var array core features.
*/
private $corefeatures = array(
'feedback_editpdf_behat_test1' => '/test/moodle/mod/assign/feedback/editpdf/tests/behat/behat_test1.feature',
'feedback_file_behat_test2' => "C:\\test\\moodle\\mod\\assign\\feedback\\file\\tests\\behat\\behat_test2.feature",
'moodle_login_behat_test3' => "C:\\test\\moodle/login/tests/behat/behat_test3.feature",
);
/**
* @var array theme features.
*/
private $themefeatures = array(
'behat_themetest1_core_behat_tests_testtheme_theme' => '/test/moodle/theme/testtheme/tests/behat/core/behat_themetest1.feature',
'behat_themetest2_mod_assign_behat_tests_testtheme_theme' => "C:\\test\\moodle\\theme\\testtheme\\tests\\behat\\mod_assign\\behat_themetest2.feature",
'behat_themetest3_behat_tests_testtheme_theme_moodle' => "C:\\test\\moodle/theme/testtheme/tests/behat/behat_themetest3.feature",
);
/**
* @var array core contexts.
*/
private $corecontexts = array(
'behat_context1' => '/test/moodle/mod/assign/feedback/editpdf/tests/behat/behat_context1.php',
'behat_context2' => "C:\\test\\moodle\\blocks\\comments\\tests\\behat\\behat_context2.php",
'behat_context3' => "C:\\test\\moodle/lib/editor/atto/tests/behat/behat_context3.php",
);
/**
* @var array Theme contexts for test.
*/
private $themecontexts = array(
'behat_theme_testtheme_behat_context1' =>
'/test/moodle/theme/testtheme/tests/behat/mod_assign/behat_theme_testtheme_behat_context1.php',
'behat_theme_testtheme_behat_context2' =>
"C:\\test\\moodle\\theme\\testtheme\\tests\\behat\\block_comments\\behat_theme_testtheme_behat_context2.php",
'behat_theme_testtheme_behat_context3' =>
"C:\\test\\moodle/theme/testtheme/tests/behat/editor_atto/behat_theme_testtheme_behat_context3.php"
);
/**
* Keep instance of behat_config_util mock object.
*
* @var null
*/
private $behatconfigutil = null;
/**
* Test setup.
*/
public function setUp() {
$this->resetAfterTest(true);
$mockbuilder = $this->getMockBuilder('behat_config_util');
$mockbuilder->setMethods(array('get_behat_features_for_theme', 'get_behat_contexts_for_theme',
'get_list_of_themes', 'get_overridden_theme_contexts'));
$this->behatconfigutil = $mockbuilder->getMock();
// List of themes is const for test.
$this->behatconfigutil->expects($this->any())
->method('get_list_of_themes')
->will($this->returnValue(array('testtheme')));
$this->behatconfigutil->expects($this->any())
->method('get_behat_contexts_for_theme')
->with($this->equalTo('testtheme'))
->will($this->returnValue(array_keys($this->themecontexts)));
}
/**
* Behat config for single run.
*
*/
public function test_get_config_file_contents_with_single_run() {
global $CFG;
$CFG->behat_wwwroot = 'http://example.com/behat';
$behatconfigutil = $this->behatconfigutil;
// No theme feature exists.
$behatconfigutil->expects($this->once())
->method('get_behat_features_for_theme')
->with($this->anything())
->will($this->returnValue(array(array(), array())));
$config = $behatconfigutil->get_config_file_contents($this->corefeatures, $this->corecontexts);
$expectedconfigwithfeatures = "default:
formatters:
moodle_progress:
output_styles:
comment:
- magenta
suites:
default:
paths:
- /test/moodle/mod/assign/feedback/editpdf/tests/behat/behat_test1.feature
- 'C:\\test\\moodle\\mod\\assign\\feedback\\file\\tests\\behat\\behat_test2.feature'
- 'C:\\test\\moodle/login/tests/behat/behat_test3.feature'
contexts:
- behat_context1
- behat_context2
- behat_context3
testtheme:
paths: { }
contexts:
- behat_theme_testtheme_behat_context1
- behat_theme_testtheme_behat_context2
- behat_theme_testtheme_behat_context3
extensions:
Behat\\MinkExtension:
base_url: 'http://example.com/behat'
goutte: null
selenium2:
wd_host: 'http://localhost:4444/wd/hub'
";
$this->assertContains($expectedconfigwithfeatures, $config);
$expectedstepdefinitions = "steps_definitions:
behat_context1: /test/moodle/mod/assign/feedback/editpdf/tests/behat/behat_context1.php
behat_context2: 'C:\\test\\moodle\\blocks\\comments\\tests\\behat\\behat_context2.php'
behat_context3: 'C:\\test\\moodle/lib/editor/atto/tests/behat/behat_context3.php'
";
$this->assertContains($expectedstepdefinitions, $config);
}
/**
* Behat config for parallel run.
*/
public function test_get_config_file_contents_with_parallel_run() {
global $CFG;
$CFG->behat_wwwroot = 'http://example.com/behat';
$behatconfigutil = $this->behatconfigutil;
// No theme feature exists.
$behatconfigutil->expects($this->any())
->method('get_behat_features_for_theme')
->with($this->anything())
->will($this->returnValue(array(array(), array())));
$config = $behatconfigutil->get_config_file_contents($this->corefeatures, $this->corecontexts, '', 3, 1);
// First run.
$this->assertContains('/test/moodle/mod/assign/feedback/editpdf/tests/behat/behat_test1.feature',
$config);
$this->assertNotContains('C:\\test\\moodle\\mod\\assign\\feedback\\file\\tests\\behat\\behat_test2.feature',
$config);
$this->assertNotContains('C:\\test\\moodle/login/tests/behat/behat_test3.feature',
$config);
// Second run.
$config = $behatconfigutil->get_config_file_contents($this->corefeatures, $this->corecontexts, '', 3, 2);
$this->assertNotContains('/test/moodle/mod/assign/feedback/editpdf/tests/behat/behat_test1.feature',
$config);
$this->assertContains('C:\\test\\moodle\\mod\\assign\\feedback\\file\\tests\\behat\\behat_test2.feature',
$config);
$this->assertNotContains('C:\\test\\moodle/login/tests/behat/behat_test3.feature',
$config);
$config = $behatconfigutil->get_config_file_contents($this->corefeatures, $this->corecontexts, '', 3, 3);
$this->assertNotContains('/test/moodle/mod/assign/feedback/editpdf/tests/behat/behat_test1.feature',
$config);
$this->assertNotContains('C:\\test\\moodle\\mod\\assign\\feedback\\file\\tests\\behat\\behat_test2.feature',
$config);
$this->assertContains('C:\\test\\moodle/login/tests/behat/behat_test3.feature',
$config);
}
/**
* Behat config with theme features.
*/
public function test_get_config_file_contents_with_theme_features() {
global $CFG;
$behatconfigutil = $this->behatconfigutil;
$suitefeatures = array_merge($this->corefeatures, $this->themefeatures);
$themefeatures = $this->themefeatures;
$behatconfigutil->expects($this->once())
->method('get_behat_features_for_theme')
->with($this->equalTo('testtheme'))
->will($this->returnValue(array(array(), $themefeatures)));
$behatconfigutil->expects($this->once())
->method('get_behat_contexts_for_theme')
->with($this->equalTo('testtheme'))
->will($this->returnValue(array_keys($this->themecontexts)));
$behatconfigutil->expects($this->once())
->method('get_overridden_theme_contexts')
->will($this->returnValue($this->themecontexts));
$behatconfigutil->set_theme_suite_to_include_core_features(true);
$CFG->behat_wwwroot = 'http://example.com/behat';
$config = $behatconfigutil->get_config_file_contents($suitefeatures, $this->corecontexts);
$expectedconfigwithfeatures = "default:
formatters:
moodle_progress:
output_styles:
comment:
- magenta
suites:
default:
paths:
- /test/moodle/mod/assign/feedback/editpdf/tests/behat/behat_test1.feature
- 'C:\\test\\moodle\\mod\\assign\\feedback\\file\\tests\\behat\\behat_test2.feature'
- 'C:\\test\\moodle/login/tests/behat/behat_test3.feature'
contexts:
- behat_context1
- behat_context2
- behat_context3
testtheme:
paths:
- /test/moodle/mod/assign/feedback/editpdf/tests/behat/behat_test1.feature
- 'C:\\test\\moodle\\mod\\assign\\feedback\\file\\tests\\behat\\behat_test2.feature'
- 'C:\\test\\moodle/login/tests/behat/behat_test3.feature'
- /test/moodle/theme/testtheme/tests/behat/core/behat_themetest1.feature
- 'C:\\test\\moodle\\theme\\testtheme\\tests\\behat\\mod_assign\\behat_themetest2.feature'
- 'C:\\test\\moodle/theme/testtheme/tests/behat/behat_themetest3.feature'
contexts:
- behat_theme_testtheme_behat_context1
- behat_theme_testtheme_behat_context2
- behat_theme_testtheme_behat_context3
extensions:
Behat\\MinkExtension:
base_url: 'http://example.com/behat'
goutte: null
selenium2:
wd_host: 'http://localhost:4444/wd/hub'
";
$this->assertContains($expectedconfigwithfeatures, $config);
$expectedstepdefinitions = "steps_definitions:
behat_context1: /test/moodle/mod/assign/feedback/editpdf/tests/behat/behat_context1.php
behat_context2: 'C:\\test\\moodle\\blocks\\comments\\tests\\behat\\behat_context2.php'
behat_context3: 'C:\\test\\moodle/lib/editor/atto/tests/behat/behat_context3.php'
behat_theme_testtheme_behat_context1: /test/moodle/theme/testtheme/tests/behat/mod_assign/behat_theme_testtheme_behat_context1.php
behat_theme_testtheme_behat_context2: 'C:\\test\\moodle\\theme\\testtheme\\tests\\behat\\block_comments\\behat_theme_testtheme_behat_context2.php'
behat_theme_testtheme_behat_context3: 'C:\\test\\moodle/theme/testtheme/tests/behat/editor_atto/behat_theme_testtheme_behat_context3.php'";
$this->assertContains($expectedstepdefinitions, $config);
}
/**
* Behat config for parallel run.
*/
public function test_get_config_file_contents_with_theme_and_parallel_run() {
global $CFG;
$CFG->behat_wwwroot = 'http://example.com/behat';
$behatconfigutil = $this->behatconfigutil;
$features = array_merge($this->corefeatures, $this->themefeatures);
$themefeatures = $this->themefeatures;
$behatconfigutil->expects($this->atLeastOnce())
->method('get_behat_features_for_theme')
->with($this->equalTo('testtheme'))
->will($this->returnValue(array(array(), $themefeatures)));
$behatconfigutil->expects($this->atLeastOnce())
->method('get_behat_contexts_for_theme')
->with($this->equalTo('testtheme'))
->will($this->returnValue(array_keys($this->themecontexts)));
$CFG->behat_wwwroot = 'http://example.com/behat';
$behatconfigutil->set_theme_suite_to_include_core_features(false);
$config = $behatconfigutil->get_config_file_contents($features, $this->themecontexts, '', 3, 1);
// First run.
$this->assertContains('/test/moodle/mod/assign/feedback/editpdf/tests/behat/behat_test1.feature',
$config);
$this->assertNotContains('C:\\test\\moodle\\mod\\assign\\feedback\\file\\tests\\behat\\behat_test2.feature',
$config);
$this->assertNotContains('C:\\test\\moodle/login/tests/behat/behat_test3.feature',
$config);
// Theme suite features.
$this->assertContains('/test/moodle/theme/testtheme/tests/behat/core/behat_themetest1.feature',
$config);
$this->assertNotContains('C:\\test\\moodle\\theme\\testtheme\\tests\\behat\\mod_assign\\behat_themetest2.feature',
$config);
$this->assertNotContains('C:\\test\\moodle/theme/testtheme/tests/behat/behat_themetest3.feature',
$config);
// Second run.
$config = $behatconfigutil->get_config_file_contents($features, $this->themecontexts, '', 3, 2);
$this->assertNotContains('/test/moodle/mod/assign/feedback/editpdf/tests/behat/behat_test1.feature',
$config);
$this->assertContains('C:\\test\\moodle\\mod\\assign\\feedback\\file\\tests\\behat\\behat_test2.feature',
$config);
$this->assertNotContains('C:\\test\\moodle/login/tests/behat/behat_test3.feature',
$config);
// Theme suite features.
$this->assertNotContains('/test/moodle/theme/testtheme/tests/behat/core/behat_themetest1.feature',
$config);
$this->assertContains('C:\\test\\moodle\\theme\\testtheme\\tests\\behat\\mod_assign\\behat_themetest2.feature',
$config);
$this->assertNotContains('C:\\test\\moodle/theme/testtheme/tests/behat/behat_themetest3.feature',
$config);
}
/**
* Test if clean features key and path is returned.
* @dataProvider clean_features_path_list
*/
public function test_get_clean_feature_key_and_path($featurepath, $key, $cleanfeaturepath) {
global $CFG;
// This is a hack so directory name is correctly detected in tests.
$CFG->dirroot = 'C:';
$behatconfigutil = $this->behatconfigutil;
// Fix expected directory path for OS.
$cleanfeaturepath = str_replace('\\', DIRECTORY_SEPARATOR, $cleanfeaturepath);
$cleanfeaturepath = str_replace('/', DIRECTORY_SEPARATOR, $cleanfeaturepath);
if (testing_is_cygwin()) {
$featurepath = str_replace('\\', '/', $cleanfeaturepath);
}
list($retkey, $retcleanfeaturepath) = $behatconfigutil->get_clean_feature_key_and_path($featurepath);
$this->assertEquals($key, $retkey);
$this->assertEquals($cleanfeaturepath, $retcleanfeaturepath);
}
public function clean_features_path_list() {
return array(
['/home/test/this/that/test/behat/mod_assign.feature', 'mod_assign_behat_test_that_this_test', '/home/test/this/that/test/behat/mod_assign.feature'],
['/home/this/that/test/behat/mod_assign.feature', 'mod_assign_behat_test_that_this_home', '/home/this/that/test/behat/mod_assign.feature'],
['/home/that/test/behat/mod_assign.feature', 'mod_assign_behat_test_that_home', '/home/that/test/behat/mod_assign.feature'],
['/home/test/behat/mod_assign.feature', 'mod_assign_behat_test_home', '/home/test/behat/mod_assign.feature'],
['mod_assign.feature', 'mod_assign', 'mod_assign.feature'],
['C:\test\this\that\test\behat\mod_assign.feature', 'mod_assign_behat_test_that_this_test', 'C:\test\this\that\test\behat\mod_assign.feature'],
['C:\this\that\test\behat\mod_assign.feature', 'mod_assign_behat_test_that_this', 'C:\this\that\test\behat\mod_assign.feature'],
['C:\that\test\behat\mod_assign.feature', 'mod_assign_behat_test_that', 'C:\that\test\behat\mod_assign.feature'],
['C:\test\behat\mod_assign.feature', 'mod_assign_behat_test', 'C:\test\behat\mod_assign.feature'],
['C:\mod_assign.feature', 'mod_assign', 'C:\mod_assign.feature'],
);
}
}
// @codeCoverageIgnoreEnd

View file

@ -25,9 +25,7 @@
defined('MOODLE_INTERNAL') || die(); defined('MOODLE_INTERNAL') || die();
require_once(__DIR__ . '/../lib.php'); require_once(__DIR__ . '/behat_config_util.php');
require_once(__DIR__ . '/behat_command.php');
require_once(__DIR__ . '/../../testing/classes/tests_finder.php');
/** /**
* Behat configuration manager * Behat configuration manager
@ -47,6 +45,24 @@ class behat_config_manager {
*/ */
public static $autoprofileconversion = false; public static $autoprofileconversion = false;
/**
* @var behat_config_util keep object of behat_config_util for use.
*/
public static $behatconfigutil = null;
/**
* Returns behat_config_util.
*
* @return behat_config_util
*/
private static function get_behat_config_util() {
if (!self::$behatconfigutil) {
self::$behatconfigutil = new behat_config_util();
}
return self::$behatconfigutil;
}
/** /**
* Updates a config file * Updates a config file
* *
@ -59,9 +75,14 @@ class behat_config_manager {
* @param string $component Restricts the obtained steps definitions to the specified component * @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 * @param string $testsrunner If the config file will be used to run tests
* @param string $tags features files including tags. * @param string $tags features files including tags.
* @param bool $themesuitewithallfeatures if only theme specific features need to be included in the suite.
* @param int $parallelruns number of parallel runs.
* @param int $run current run for which config needs to be updated.
* @return void * @return void
*/ */
public static function update_config_file($component = '', $testsrunner = true, $tags = '') { public static function update_config_file($component = '', $testsrunner = true, $tags = '',
$themesuitewithallfeatures = false, $parallelruns = 0, $run = 0) {
global $CFG; global $CFG;
// Behat must have a separate behat.yml to have access to the whole set of features and steps definitions. // Behat must have a separate behat.yml to have access to the whole set of features and steps definitions.
@ -72,49 +93,36 @@ class behat_config_manager {
$configfilepath = self::get_steps_list_config_filepath(); $configfilepath = self::get_steps_list_config_filepath();
} }
// Gets all the components with features. $behatconfigutil = self::get_behat_config_util();
$behatconfigutil->set_theme_suite_to_include_core_features($themesuitewithallfeatures);
$behatconfigutil->set_tag_for_feature_filter($tags);
// Gets all the components with features, if running the tests otherwise not required.
$features = array(); $features = array();
$components = tests_finder::get_components_with_tests('features'); if ($testsrunner) {
if ($components) { $features = $behatconfigutil->get_components_features();
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;
}
}
foreach ($featurespaths as $path) {
$additional = glob("$path/*.feature");
$features = array_merge($features, $additional);
}
}
// Optionally include features from additional directories.
if (!empty($CFG->behat_additionalfeatures)) {
$features = array_merge($features, array_map("realpath", $CFG->behat_additionalfeatures));
} }
// Gets all the components with steps definitions. // Gets all the components with steps definitions.
$stepsdefinitions = array(); $stepsdefinitions = $behatconfigutil->get_components_contexts($component);
$steps = self::get_components_steps_definitions();
if ($steps) {
foreach ($steps as $key => $filepath) {
if ($component == '' || $component === $key) {
$stepsdefinitions[$key] = $filepath;
}
}
}
// We don't want the deprecated steps definitions here. // We don't want the deprecated steps definitions here.
if (!$testsrunner) { if (!$testsrunner) {
unset($stepsdefinitions['behat_deprecated']); unset($stepsdefinitions['behat_deprecated']);
} }
// Get current run.
if (empty($run) && ($run !== false) && !empty($CFG->behatrunprocess)) {
$run = $CFG->behatrunprocess;
}
// Get number of parallel runs if not passed.
if (empty($parallelruns) && ($parallelruns !== false)) {
$parallelruns = self::get_parallel_test_runs();
}
// Behat config file specifing the main context class, // Behat config file specifing the main context class,
// the required Behat extensions and Moodle test wwwroot. // the required Behat extensions and Moodle test wwwroot.
$contents = self::get_config_file_contents(self::get_features_with_tags($features, $tags), $stepsdefinitions); $contents = $behatconfigutil->get_config_file_contents($features, $stepsdefinitions, $tags, $parallelruns, $run);
// Stores the file. // Stores the file.
if (!file_put_contents($configfilepath, $contents)) { if (!file_put_contents($configfilepath, $contents)) {
@ -129,55 +137,13 @@ class behat_config_manager {
* @param array $features set of feature files. * @param array $features set of feature files.
* @param string $tags list of tags (currently support && only.) * @param string $tags list of tags (currently support && only.)
* @return array filtered list of feature files with tags. * @return array filtered list of feature files with tags.
* @deprecated since 3.2 MDL-55072 - please use behat_config_util.php
* @todo MDL-55365 This will be deleted in Moodle 3.6.
*/ */
public static function get_features_with_tags($features, $tags) { public static function get_features_with_tags($features, $tags) {
if (empty($tags)) {
return $features;
}
$newfeaturelist = array();
// Split tags in and and or.
$tags = explode('&&', $tags);
$andtags = array();
$ortags = array();
foreach ($tags as $tag) {
// Explode all tags seperated by , and add it to ortags.
$ortags = array_merge($ortags, explode(',', $tag));
// And tags will be the first one before comma(,).
$andtags[] = preg_replace('/,.*/', '', $tag);
}
foreach ($features as $featurefile) { debugging('Use of get_features_with_tags is deprecated, please see behat_config_util', DEBUG_DEVELOPER);
$contents = file_get_contents($featurefile); return self::get_behat_config_util()->filtered_features_with_tags($features, $tags);
$includefeature = true;
foreach ($andtags as $tag) {
// If negitive tag, then ensure it don't exist.
if (strpos($tag, '~') !== false) {
$tag = substr($tag, 1);
if ($contents && strpos($contents, $tag) !== false) {
$includefeature = false;
break;
}
} else if ($contents && strpos($contents, $tag) === false) {
$includefeature = false;
break;
}
}
// If feature not included then check or tags.
if (!$includefeature && !empty($ortags)) {
foreach ($ortags as $tag) {
if ($contents && (strpos($tag, '~') === false) && (strpos($contents, $tag) !== false)) {
$includefeature = true;
break;
}
}
}
if ($includefeature) {
$newfeaturelist[] = $featurefile;
}
}
return $newfeaturelist;
} }
/** /**
@ -189,32 +155,14 @@ class behat_config_manager {
* it from the steps definitions web interface * it from the steps definitions web interface
* *
* @return array * @return array
* @deprecated since 3.2 MDL-55072 - please use behat_config_util.php
* @todo MDL-55365 This will be deleted in Moodle 3.6.
*/ */
public static function get_components_steps_definitions() { public static function get_components_steps_definitions() {
$components = tests_finder::get_components_with_tests('stepsdefinitions'); debugging('Use of get_components_steps_definitions is deprecated, please see behat_config_util::get_components_contexts',
if (!$components) { DEBUG_DEVELOPER);
return false; return self::get_behat_config_util()->get_components_contexts();
}
$stepsdefinitions = array();
foreach ($components as $componentname => $componentpath) {
$componentpath = self::clean_path($componentpath);
if (!file_exists($componentpath . self::get_behat_tests_path())) {
continue;
}
$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;
} }
/** /**
@ -361,91 +309,13 @@ class behat_config_manager {
* @param array $features The system feature files * @param array $features The system feature files
* @param array $stepsdefinitions The system steps definitions * @param array $stepsdefinitions The system steps definitions
* @return string * @return string
* @deprecated since 3.2 MDL-55072 - please use behat_config_util.php
* @todo MDL-55365 This will be deleted in Moodle 3.6.
*/ */
protected static function get_config_file_contents($features, $stepsdefinitions) { protected static function get_config_file_contents($features, $stepsdefinitions) {
global $CFG;
// We require here when we are sure behat dependencies are available. debugging('Use of get_config_file_contents is deprecated, please see behat_config_util', DEBUG_DEVELOPER);
require_once($CFG->dirroot . '/vendor/autoload.php'); return self::get_behat_config_util()->get_config_file_contents($features, $stepsdefinitions);
$selenium2wdhost = array('wd_host' => 'http://localhost:4444/wd/hub');
$parallelruns = self::get_parallel_test_runs();
// If parallel run, then only divide features.
if (!empty($CFG->behatrunprocess) && !empty($parallelruns)) {
// Attempt to split into weighted buckets using timing information, if available.
if ($alloc = self::profile_guided_allocate($features, max(1, $parallelruns), $CFG->behatrunprocess)) {
$features = $alloc;
} else {
// Divide the list of feature files amongst the parallel runners.
srand(crc32(floor(time() / 3600 / 24) . var_export($features, true)));
shuffle($features);
// Pull out the features for just this worker.
if (count($features)) {
$features = array_chunk($features, ceil(count($features) / max(1, $parallelruns)));
// Check if there is any feature file for this process.
if (!empty($features[$CFG->behatrunprocess - 1])) {
$features = $features[$CFG->behatrunprocess - 1];
} else {
$features = null;
}
}
}
// Set proper selenium2 wd_host if defined.
if (!empty($CFG->behat_parallel_run[$CFG->behatrunprocess - 1]['wd_host'])) {
$selenium2wdhost = array('wd_host' => $CFG->behat_parallel_run[$CFG->behatrunprocess - 1]['wd_host']);
}
}
// It is possible that it has no value as we don't require a full behat setup to list the step definitions.
if (empty($CFG->behat_wwwroot)) {
$CFG->behat_wwwroot = 'http://itwillnotbeused.com';
}
// Comments use black color, so failure path is not visible. Using color other then black/white is safer.
// https://github.com/Behat/Behat/pull/628.
$config = array(
'default' => array(
'formatters' => array(
'moodle_progress' => array(
'output_styles' => array(
'comment' => array('magenta'))
)
),
'suites' => array(
'default' => array(
'paths' => $features,
'contexts' => array_keys($stepsdefinitions)
)
),
'extensions' => array(
'Behat\MinkExtension' => array(
'base_url' => $CFG->behat_wwwroot,
'goutte' => null,
'selenium2' => $selenium2wdhost
),
'Moodle\BehatExtension' => array(
'moodledirroot' => $CFG->dirroot,
'steps_definitions' => $stepsdefinitions
)
)
)
);
// In case user defined overrides respect them over our default ones.
if (!empty($CFG->behat_config)) {
foreach ($CFG->behat_config as $profile => $values) {
$config = self::merge_config($config, self::merge_behat_config($profile, $values));
}
}
// Check for Moodle custom ones.
if (!empty($CFG->behat_profiles) && is_array($CFG->behat_profiles)) {
foreach ($CFG->behat_profiles as $profile => $values) {
$config = self::merge_config($config, self::get_behat_profile($profile, $values));
}
}
return Symfony\Component\Yaml\Yaml::dump($config, 10, 2);
} }
/** /**
@ -454,41 +324,13 @@ class behat_config_manager {
* @param string $profile profile name * @param string $profile profile name
* @param array $values values for profile * @param array $values values for profile
* @return array * @return array
* @deprecated since 3.2 MDL-55072 - please use behat_config_util.php
* @todo MDL-55365 This will be deleted in Moodle 3.6.
*/ */
protected static function merge_behat_config($profile, $values) { protected static function merge_behat_config($profile, $values) {
// Only add profile which are compatible with Behat 3.x
// Just check if any of Bheat 2.5 config is set. Not checking for 3.x as it might have some other configs
// Like : rerun_cache etc.
if (!isset($values['filters']['tags']) && !isset($values['extensions']['Behat\MinkExtension\Extension'])) {
return array($profile => $values);
}
// Parse 2.5 format and get related values. debugging('Use of merge_behat_config is deprecated, please see behat_config_util', DEBUG_DEVELOPER);
$oldconfigvalues = array(); self::get_behat_config_util()->get_behat_config_for_profile($profile, $values);
if (isset($values['extensions']['Behat\MinkExtension\Extension'])) {
$extensionvalues = $values['extensions']['Behat\MinkExtension\Extension'];
if (isset($extensionvalues['selenium2']['browser'])) {
$oldconfigvalues['browser'] = $extensionvalues['selenium2']['browser'];
}
if (isset($extensionvalues['selenium2']['wd_host'])) {
$oldconfigvalues['wd_host'] = $extensionvalues['selenium2']['wd_host'];
}
if (isset($extensionvalues['capabilities'])) {
$oldconfigvalues['capabilities'] = $extensionvalues['capabilities'];
}
}
if (isset($values['filters']['tags'])) {
$oldconfigvalues['tags'] = $values['filters']['tags'];
}
if (!empty($oldconfigvalues)) {
self::$autoprofileconversion = true;
return self::get_behat_profile($profile, $oldconfigvalues);
}
// If nothing set above then return empty array.
return array();
} }
/** /**
@ -569,64 +411,8 @@ class behat_config_manager {
*/ */
protected static function profile_guided_allocate($features, $nbuckets, $instance) { protected static function profile_guided_allocate($features, $nbuckets, $instance) {
$behattimingfile = defined('BEHAT_FEATURE_TIMING_FILE') && debugging('Use of profile_guided_allocate is deprecated, please see behat_config_util', DEBUG_DEVELOPER);
@filesize(BEHAT_FEATURE_TIMING_FILE) ? BEHAT_FEATURE_TIMING_FILE : false; return self::get_behat_config_util()->profile_guided_allocate($features, $nbuckets, $instance);
if (!$behattimingfile || !$behattimingdata = @json_decode(file_get_contents($behattimingfile), true)) {
// No data available, fall back to relying on steps data.
$stepfile = "";
if (defined('BEHAT_FEATURE_STEP_FILE') && BEHAT_FEATURE_STEP_FILE) {
$stepfile = BEHAT_FEATURE_STEP_FILE;
}
// We should never get this. But in case we can't do this then fall back on simple splitting.
if (empty($stepfile) || !$behattimingdata = @json_decode(file_get_contents($stepfile), true)) {
return false;
}
}
arsort($behattimingdata); // Ensure most expensive is first.
$realroot = realpath(__DIR__.'/../../../').'/';
$defaultweight = array_sum($behattimingdata) / count($behattimingdata);
$weights = array_fill(0, $nbuckets, 0);
$buckets = array_fill(0, $nbuckets, array());
$totalweight = 0;
// Re-key the features list to match timing data.
foreach ($features as $k => $file) {
$key = str_replace($realroot, '', $file);
$features[$key] = $file;
unset($features[$k]);
if (!isset($behattimingdata[$key])) {
$behattimingdata[$key] = $defaultweight;
}
}
// Sort features by known weights; largest ones should be allocated first.
$behattimingorder = array();
foreach ($features as $key => $file) {
$behattimingorder[$key] = $behattimingdata[$key];
}
arsort($behattimingorder);
// Finally, add each feature one by one to the lightest bucket.
foreach ($behattimingorder as $key => $weight) {
$file = $features[$key];
$lightbucket = array_search(min($weights), $weights);
$weights[$lightbucket] += $weight;
$buckets[$lightbucket][] = $file;
$totalweight += $weight;
}
if ($totalweight && !defined('BEHAT_DISABLE_HISTOGRAM') && $instance == $nbuckets) {
echo "Bucket weightings:\n";
foreach ($weights as $k => $weight) {
echo $k + 1 . ": " . str_repeat('*', 70 * $nbuckets * $weight / $totalweight) . PHP_EOL;
}
}
// Return the features for this worker.
return $buckets[$instance - 1];
} }
/** /**
@ -637,34 +423,13 @@ class behat_config_manager {
* @param mixed $config The node of the default config * @param mixed $config The node of the default config
* @param mixed $localconfig The node of the local config * @param mixed $localconfig The node of the local config
* @return mixed The merge result * @return mixed The merge result
* @deprecated since 3.2 MDL-55072 - please use behat_config_util.php
* @todo MDL-55365 This will be deleted in Moodle 3.6.
*/ */
protected static function merge_config($config, $localconfig) { protected static function merge_config($config, $localconfig) {
if (!is_array($config) && !is_array($localconfig)) { debugging('Use of merge_config is deprecated, please see behat_config_util', DEBUG_DEVELOPER);
return $localconfig; return self::get_behat_config_util()->merge_config($config, $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;
} }
/** /**
@ -673,28 +438,25 @@ class behat_config_manager {
* @see tests_finder::get_all_directories_with_tests() it returns the path including /tests/ * @see tests_finder::get_all_directories_with_tests() it returns the path including /tests/
* @param string $path * @param string $path
* @return string The string without the last /tests part * @return string The string without the last /tests part
* @deprecated since 3.2 MDL-55072 - please use behat_config_util.php
* @todo MDL-55365 This will be deleted in Moodle 3.6.
*/ */
protected final static function clean_path($path) { protected final static function clean_path($path) {
$path = rtrim($path, DIRECTORY_SEPARATOR); debugging('Use of clean_path is deprecated, please see behat_config_util', DEBUG_DEVELOPER);
return self::get_behat_config_util()->clean_path($path);
$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 * The relative path where components stores their behat tests
* *
* @return string * @return string
* @deprecated since 3.2 MDL-55072 - please use behat_config_util.php
* @todo MDL-55365 This will be deleted in Moodle 3.6.
*/ */
protected final static function get_behat_tests_path() { protected final static function get_behat_tests_path() {
return DIRECTORY_SEPARATOR . 'tests' . DIRECTORY_SEPARATOR . 'behat'; debugging('Use of get_behat_tests_path is deprecated, please see behat_config_util', DEBUG_DEVELOPER);
return self::get_behat_config_util()->get_behat_tests_path();
} }
} }

File diff suppressed because it is too large Load diff

View file

@ -55,8 +55,22 @@ class behat_context_helper {
* *
* @param Environment $environment * @param Environment $environment
* @return void * @return void
* @deprecated since 3.2 MDL-55072 - please use behat_context_helper::set_environment()
* @todo MDL-55365 This will be deleted in Moodle 3.6.
*/ */
public static function set_session(Environment $environment) { public static function set_session(Environment $environment) {
debugging('set_session is deprecated. Please use set_environment instead.', DEBUG_DEVELOPER);
self::set_environment($environment);
}
/**
* Sets behat environment.
*
* @param Environment $environment
* @return void
*/
public static function set_environment(Environment $environment) {
self::$environment = $environment; self::$environment = $environment;
} }
@ -67,17 +81,27 @@ class behat_context_helper {
* that uses direct API calls; steps returning step chains * that uses direct API calls; steps returning step chains
* can not be executed like this. * can not be executed like this.
* *
* @throws coding_exception * @throws Behat\Behat\Context\Exception\ContextNotFoundException
* @param string $classname Context identifier (the class name). * @param string $classname Context identifier (the class name).
* @return behat_base * @return behat_base
*/ */
public static function get($classname) { public static function get($classname) {
if (!$subcontext = self::$environment->getContext($classname)) { $suitename = self::$environment->getSuite()->getName();
throw coding_exception('The required "' . $classname . '" class does not exist'); $overridencontextname = 'behat_theme_'.$suitename.'_'.$classname;
// Check if overridden context class exists.
if ($suitename !== 'default') {
try {
$subcontext = self::$environment->getContext($overridencontextname);
return $subcontext;
} catch (Behat\Behat\Context\Exception\ContextNotFoundException $e) {
// If context not found then it's not overridden.
}
} }
return $subcontext; // Get the actual context.
return self::$environment->getContext($classname);
} }
/** /**

View file

@ -23,7 +23,6 @@
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/ */
defined('MOODLE_INTERNAL') || die();
/** /**
* Moodle selectors manager. * Moodle selectors manager.

View file

@ -215,10 +215,13 @@ class behat_util extends testing_util {
* *
* Stores a file in dataroot/behat to allow Moodle to switch * Stores a file in dataroot/behat to allow Moodle to switch
* to the test environment when using cli-server. * to the test environment when using cli-server.
* @param bool $themesuitewithallfeatures if only theme specific features need to be included in the suite.
* @param int $parallelruns number of parallel runs.
* @param int $run current run.
* @throws coding_exception * @throws coding_exception
* @return void * @return void
*/ */
public static function start_test_mode() { public static function start_test_mode($themesuitewithallfeatures = false, $parallelruns = 0, $run = 0) {
global $CFG; global $CFG;
if (!defined('BEHAT_UTIL')) { if (!defined('BEHAT_UTIL')) {
@ -234,7 +237,7 @@ class behat_util extends testing_util {
self::test_environment_problem(); self::test_environment_problem();
// Updates all the Moodle features and steps definitions. // Updates all the Moodle features and steps definitions.
behat_config_manager::update_config_file(); behat_config_manager::update_config_file('', true, '', $themesuitewithallfeatures, $parallelruns, $run);
if (self::is_test_mode_enabled()) { if (self::is_test_mode_enabled()) {
return; return;

View file

@ -197,6 +197,9 @@ class tests_finder {
case 'stepsdefinitions': case 'stepsdefinitions':
$regexp = '|'.$sep.'tests'.$sep.'behat'.$sep.'behat_.*\.php$|'; $regexp = '|'.$sep.'tests'.$sep.'behat'.$sep.'behat_.*\.php$|';
break; break;
case 'behat':
$regexp = '!'.$sep.'tests'.$sep.'behat'.$sep.'(.*\.feature)|(behat_.*\.php)$!';
break;
} }
return $regexp; return $regexp;

View file

@ -96,6 +96,13 @@ class behat_hooks extends behat_base {
*/ */
protected static $timings = array(); protected static $timings = array();
/**
* Keeps track of current running suite name.
*
* @var string current running suite name
*/
protected static $runningsuite = '';
/** /**
* Hook to capture BeforeSuite event so as to give access to moodle codebase. * Hook to capture BeforeSuite event so as to give access to moodle codebase.
* This will try and catch any exception and exists if anything fails. * This will try and catch any exception and exists if anything fails.
@ -128,15 +135,19 @@ class behat_hooks extends behat_base {
// Defined only when the behat CLI command is running, the moodle init setup process will // Defined only when the behat CLI command is running, the moodle init setup process will
// read this value and switch to $CFG->behat_dataroot and $CFG->behat_prefix instead of // read this value and switch to $CFG->behat_dataroot and $CFG->behat_prefix instead of
// the normal site. // the normal site.
if (!defined('BEHAT_TEST')) {
define('BEHAT_TEST', 1); define('BEHAT_TEST', 1);
}
if (!defined('CLI_SCRIPT')) {
define('CLI_SCRIPT', 1); define('CLI_SCRIPT', 1);
}
// With BEHAT_TEST we will be using $CFG->behat_* instead of $CFG->dataroot, $CFG->prefix and $CFG->wwwroot. // With BEHAT_TEST we will be using $CFG->behat_* instead of $CFG->dataroot, $CFG->prefix and $CFG->wwwroot.
require_once(__DIR__ . '/../../../config.php'); require_once(__DIR__ . '/../../../config.php');
// Now that we are MOODLE_INTERNAL. // Now that we are MOODLE_INTERNAL.
require_once(__DIR__ . '/../../behat/classes/behat_command.php'); require_once(__DIR__ . '/../../behat/classes/behat_command.php');
require_once(__DIR__ . '/../../behat/classes/behat_selectors.php');
require_once(__DIR__ . '/../../behat/classes/behat_context_helper.php'); require_once(__DIR__ . '/../../behat/classes/behat_context_helper.php');
require_once(__DIR__ . '/../../behat/classes/util.php'); require_once(__DIR__ . '/../../behat/classes/util.php');
require_once(__DIR__ . '/../../testing/classes/test_lock.php'); require_once(__DIR__ . '/../../testing/classes/test_lock.php');
@ -264,7 +275,7 @@ class behat_hooks extends behat_base {
* @throws behat_stop_exception If here we are not using the test database it should be because of a coding error * @throws behat_stop_exception If here we are not using the test database it should be because of a coding error
*/ */
public function before_scenario(BeforeScenarioScope $scope) { public function before_scenario(BeforeScenarioScope $scope) {
global $DB, $SESSION, $CFG; global $DB, $CFG;
// As many checks as we can. // As many checks as we can.
if (!defined('BEHAT_TEST') || if (!defined('BEHAT_TEST') ||
@ -290,10 +301,18 @@ class behat_hooks extends behat_base {
throw new behat_stop_exception($e->getMessage()); throw new behat_stop_exception($e->getMessage());
} }
$suitename = $scope->getSuite()->getName();
// Register behat selectors for theme, if suite is changed. We do it for every suite change.
if ($suitename !== self::$runningsuite) {
behat_context_helper::set_environment($scope->getEnvironment());
// We need the Mink session to do it and we do it only before the first scenario. // We need the Mink session to do it and we do it only before the first scenario.
if (self::is_first_scenario()) { $behatselectorclass = behat_config_util::get_behat_theme_selector_override_classname($suitename, true);
behat_selectors::register_moodle_selectors($session); if (class_exists($behatselectorclass)) {
behat_context_helper::set_session($scope->getEnvironment()); $behatselectorclass = new $behatselectorclass();
$behatselectorclass::register_moodle_selectors($session);
}
} }
// Reset mink session between the scenarios. // Reset mink session between the scenarios.
@ -317,6 +336,12 @@ class behat_hooks extends behat_base {
} }
} }
// Set the theme if not default.
if ($suitename !== "default") {
set_config('theme', $suitename);
self::$runningsuite = $suitename;
}
// Start always in the the homepage. // Start always in the the homepage.
try { try {
// Let's be conservative as we never know when new upstream issues will affect us. // Let's be conservative as we never know when new upstream issues will affect us.
@ -325,7 +350,6 @@ class behat_hooks extends behat_base {
throw new behat_stop_exception($e->getMessage()); throw new behat_stop_exception($e->getMessage());
} }
// Checking that the root path is a Moodle test site. // Checking that the root path is a Moodle test site.
if (self::is_first_scenario()) { if (self::is_first_scenario()) {
$notestsiteexception = new behat_stop_exception('The base URL (' . $CFG->wwwroot . ') is not a behat test site, ' . $notestsiteexception = new behat_stop_exception('The base URL (' . $CFG->wwwroot . ') is not a behat test site, ' .
@ -334,6 +358,7 @@ class behat_hooks extends behat_base {
self::$initprocessesfinished = true; self::$initprocessesfinished = true;
} }
// Run all test with medium (1024x768) screen size, to avoid responsive problems. // Run all test with medium (1024x768) screen size, to avoid responsive problems.
$this->resize_window('medium'); $this->resize_window('medium');
} }

View file

@ -55,6 +55,21 @@ information provided here is intended especially for developers.
* New functions to support deprecation of events have been added to the base event. See MDL-46214 for further details. * New functions to support deprecation of events have been added to the base event. See MDL-46214 for further details.
* A new function `get_name_with_info` has been added to the base event. This function adds information about event * A new function `get_name_with_info` has been added to the base event. This function adds information about event
deprecations and should be used where this information is relevant. deprecations and should be used where this information is relevant.
* Following api's have been deprecated in behat_config_manager, please use behat_config_util instead.
- get_features_with_tags
- get_components_steps_definitions
- get_config_file_contents
- merge_behat_config
- get_behat_profile
- profile_guided_allocate
- merge_config
- clean_path
- get_behat_tests_path
* behat_util::start_test_mode() accepts 3 options now:
- 1. Theme sute with all features: If behat should initialise theme suite with all core features.
- 2. Parallel runs: How many parallel runs will be running.
- 3. Run: Which process behat should be initialise for.
* behat_context_helper::set_session() has been deprecated, please use behat_context_helper::set_environment() instead.
=== 3.1 === === 3.1 ===