diff --git a/badges/tests/behat/award_badge.feature b/badges/tests/behat/award_badge.feature index 4bb0a663dad..efbab25bd9a 100644 --- a/badges/tests/behat/award_badge.feature +++ b/badges/tests/behat/award_badge.feature @@ -221,16 +221,13 @@ Feature: Award badges And I follow "Course 1" And I press "Mark as complete: Test assignment name" And I log out - And I log in as "admin" - # We can't wait for cron to happen, so the admin manually triggers it. - And I trigger cron - # The admin needs to trigger cron twice to see the completion status as completed. - # We wait more than 1 minute because of the next cron run scheduled time. - And I wait "61" seconds - And I trigger cron - # Finally the admin goes back to homepage to continue the user story. - And I am on site homepage - And I log out + # Completion cron won't mark the whole course completed unless the + # individual criteria was marked completed more than a second ago. So + # run it twice, first to mark the criteria and second for the course. + And I run the scheduled task "core\task\completion_regular_task" + And I wait "1" seconds + And I run the scheduled task "core\task\completion_regular_task" + # The student should now see their badge. And I log in as "student1" And I follow "Profile" in the user menu Then I should see "Course Badge" diff --git a/lib/moodlelib.php b/lib/moodlelib.php index 93075e4b036..89ae5fb67ad 100644 --- a/lib/moodlelib.php +++ b/lib/moodlelib.php @@ -8404,7 +8404,7 @@ function address_in_subnet($addr, $subnetstr) { */ function mtrace($string, $eol="\n", $sleep=0) { - if (defined('STDOUT') and !PHPUNIT_TEST) { + if (defined('STDOUT') && !PHPUNIT_TEST && !defined('BEHAT_TEST')) { fwrite(STDOUT, $string.$eol); } else { echo $string . $eol; diff --git a/lib/tests/behat/behat_general.php b/lib/tests/behat/behat_general.php index 5feaa377ddd..57c63553e09 100644 --- a/lib/tests/behat/behat_general.php +++ b/lib/tests/behat/behat_general.php @@ -935,6 +935,63 @@ class behat_general extends behat_base { $this->getSession()->visit($this->locate_path('/admin/cron.php')); } + /** + * Runs a scheduled task immediately, given full class name. + * + * This is faster and more reliable than running cron (running cron won't + * work more than once in the same test, for instance). However it is + * a little less 'realistic'. + * + * While the task is running, we suppress mtrace output because it makes + * the Behat result look ugly. + * + * Note: Most of the code relating to running a task is based on + * admin/tool/task/cli/schedule_task.php. + * + * @Given /^I run the scheduled task "(?P[^"]+)"$/ + * @param string $taskname Name of task e.g. 'mod_whatever\task\do_something' + */ + public function i_run_the_scheduled_task($taskname) { + $task = \core\task\manager::get_scheduled_task($taskname); + if (!$task) { + throw new DriverException('The "' . $taskname . '" scheduled task does not exist'); + } + + // Do setup for cron task. + raise_memory_limit(MEMORY_EXTRA); + cron_setup_user(); + + // Get lock. + $cronlockfactory = \core\lock\lock_config::get_lock_factory('cron'); + if (!$cronlock = $cronlockfactory->get_lock('core_cron', 10)) { + throw new DriverException('Unable to obtain core_cron lock for scheduled task'); + } + if (!$lock = $cronlockfactory->get_lock('\\' . get_class($task), 10)) { + $cronlock->release(); + throw new DriverException('Unable to obtain task lock for scheduled task'); + } + $task->set_lock($lock); + if (!$task->is_blocking()) { + $cronlock->release(); + } else { + $task->set_cron_lock($cronlock); + } + + try { + // Discard task output as not appropriate for Behat output! + ob_start(); + $task->execute(); + ob_end_clean(); + + // Mark task complete. + \core\task\manager::scheduled_task_complete($task); + } catch (Exception $e) { + // Mark task failed and throw exception. + \core\task\manager::scheduled_task_failed($task); + throw new DriverException('The "' . $taskname . '" scheduled task failed', 0, $e); + } + } + /** * Checks that an element and selector type exists in another element and selector type on the current page. *