mirror of
https://github.com/moodle/moodle.git
synced 2025-05-04 15:27:34 +02:00
Applied the following changes to various testcase classes: - Namespaced with component[\level2-API] - Moved to level2-API subdirectory when required. - Fixed incorrect use statements with leading backslash. - Remove file phpdoc block - Remove MOODLE_INTERNAL if not needed. - Changed code to point to global scope when needed. - Fix some relative paths and comments here and there. - All them passing individually. - Complete runs passing too. Special mention to: - The following task tests have been moved within the level2 directory: - \core\adhoc_task_test => \core\task\adhoc_task_test - \core\scheduled_task_test => \core\task\scheduled_task_test - \core\calendar_cron_task_test => \core\task\calendar_cron_task_test - \core\h5p_get_content_types_task_test => \core\task\h5p_get_content_types_task_test - \core\task_database_logger_test => \core\task\database_logger_test - \core\task_logging_test => \core\task\logging_test - The following event tests have been moved within level2 directory: - \core\event_context_locked_test => \core\event\context_locked_test - \core\event_deprecated_test => \core\event\deprecated_test - \core\event_grade_deleted_test => \core\event\grade_deleted_test - \core\event_profile_field_test => \core\event\profile_field_test - \core\event_unknown_logged_test => \core\event\unknown_logged_test - \core\event_user_graded_test => \core\event\user_graded_test - \core\event_user_password_updated_test => \core\event\user_password_updated_test - The following output tests have been moved within level2 directory: - \core\mustache_template_finder_test => \core\output\mustache_template_finder_test - \core\mustache_template_source_loader_test => \core\output\mustache_template_source_loader_test - \core\output_mustache_helper_collection_test => \core\output\mustache_helper_collection_test - The following tests have been moved to their correct tests directories: - lib/tests/time_splittings_test.php => analytics/tests/time_splittings_test.php - All the classes and tests under lib/filebrowser and lib/filestorage belong to core, not to core_files. Some day we should move them to their correct subsystem. - All the classes and tests under lib/grade belong to core, not to core_grades. Some day we should move them to their correct subsystem. - The core_grades_external class and its \core\grades_external_test unit test should belong to the grades subsystem or, alternatively, to \core\external, they both should be moved together. - The core_grading_external class and its \core\grading_external_test unit test should belong to the grading subsystem or, alternatively, to \core\external, they both should be moved together. - The \core\message\message and \core\message\inbound (may be others) classes, and their associated tests should go to the core_message subsystem. - The core_user class, and its associated tests should go to the core_user subsystem. - The \core\update namespace is plain wrong (update is not valid API) and needs action 1) create it or 2) move elsewhere.
811 lines
30 KiB
PHP
811 lines
30 KiB
PHP
<?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/>.
|
|
|
|
namespace core\task;
|
|
|
|
defined('MOODLE_INTERNAL') || die();
|
|
require_once(__DIR__ . '/../fixtures/task_fixtures.php');
|
|
|
|
/**
|
|
* Test class for scheduled task.
|
|
*
|
|
* @package core
|
|
* @category test
|
|
* @copyright 2013 Damyon Wiese
|
|
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
|
*/
|
|
class scheduled_task_test extends \advanced_testcase {
|
|
|
|
/**
|
|
* Test the cron scheduling method
|
|
*/
|
|
public function test_eval_cron_field() {
|
|
$testclass = new scheduled_test_task();
|
|
|
|
$this->assertEquals(20, count($testclass->eval_cron_field('*/3', 0, 59)));
|
|
$this->assertEquals(31, count($testclass->eval_cron_field('1,*/2', 0, 59)));
|
|
$this->assertEquals(15, count($testclass->eval_cron_field('1-10,5-15', 0, 59)));
|
|
$this->assertEquals(13, count($testclass->eval_cron_field('1-10,5-15/2', 0, 59)));
|
|
$this->assertEquals(3, count($testclass->eval_cron_field('1,2,3,1,2,3', 0, 59)));
|
|
$this->assertEquals(0, count($testclass->eval_cron_field('-1,10,80', 0, 59)));
|
|
$this->assertEquals(0, count($testclass->eval_cron_field('-1', 0, 59)));
|
|
}
|
|
|
|
public function test_get_next_scheduled_time() {
|
|
global $CFG;
|
|
$this->resetAfterTest();
|
|
|
|
$this->setTimezone('Europe/London');
|
|
|
|
// Let's specify the hour we are going to use initially for the test.
|
|
// (note that we pick 01:00 that is tricky for Europe/London, because
|
|
// it's exactly the Daylight Saving Time Begins hour.
|
|
$testhour = 1;
|
|
|
|
// Test job run at 1 am.
|
|
$testclass = new scheduled_test_task();
|
|
|
|
// All fields default to '*'.
|
|
$testclass->set_hour($testhour);
|
|
$testclass->set_minute('0');
|
|
// Next valid time should be 1am of the next day.
|
|
$nexttime = $testclass->get_next_scheduled_time();
|
|
|
|
$oneamdate = new \DateTime('now', new \DateTimeZone('Europe/London'));
|
|
$oneamdate->setTime($testhour, 0, 0);
|
|
|
|
// Once a year (currently last Sunday of March), when changing to Daylight Saving Time,
|
|
// Europe/London 01:00 simply doesn't exists because, exactly at 01:00 the clock
|
|
// is advanced by one hour and becomes 02:00. When that happens, the DateInterval
|
|
// calculations cannot be to advance by 1 day, but by one less hour. That is exactly when
|
|
// the next scheduled run will happen (next day 01:00).
|
|
$isdaylightsaving = false;
|
|
if ($testhour < (int)$oneamdate->format('H')) {
|
|
$isdaylightsaving = true;
|
|
}
|
|
|
|
// Make it 1 am tomorrow if the time is after 1am.
|
|
if ($oneamdate->getTimestamp() < time()) {
|
|
$oneamdate->add(new \DateInterval('P1D'));
|
|
if ($isdaylightsaving) {
|
|
// If today is Europe/London Daylight Saving Time Begins, expectation is 1 less hour.
|
|
$oneamdate->sub(new \DateInterval('PT1H'));
|
|
}
|
|
}
|
|
$oneam = $oneamdate->getTimestamp();
|
|
|
|
$this->assertEquals($oneam, $nexttime, 'Next scheduled time is 1am.');
|
|
|
|
// Disabled flag does not affect next time.
|
|
$testclass->set_disabled(true);
|
|
$nexttime = $testclass->get_next_scheduled_time();
|
|
$this->assertEquals($oneam, $nexttime, 'Next scheduled time is 1am.');
|
|
|
|
// Now test for job run every 10 minutes.
|
|
$testclass = new scheduled_test_task();
|
|
|
|
// All fields default to '*'.
|
|
$testclass->set_minute('*/10');
|
|
// Next valid time should be next 10 minute boundary.
|
|
$nexttime = $testclass->get_next_scheduled_time();
|
|
|
|
$minutes = ((intval(date('i') / 10)) + 1) * 10;
|
|
$nexttenminutes = mktime(date('H'), $minutes, 0);
|
|
|
|
$this->assertEquals($nexttenminutes, $nexttime, 'Next scheduled time is in 10 minutes.');
|
|
|
|
// Disabled flag does not affect next time.
|
|
$testclass->set_disabled(true);
|
|
$nexttime = $testclass->get_next_scheduled_time();
|
|
$this->assertEquals($nexttenminutes, $nexttime, 'Next scheduled time is in 10 minutes.');
|
|
|
|
// Test hourly job executed on Sundays only.
|
|
$testclass = new scheduled_test_task();
|
|
$testclass->set_minute('0');
|
|
$testclass->set_day_of_week('7');
|
|
|
|
$nexttime = $testclass->get_next_scheduled_time();
|
|
|
|
$this->assertEquals(7, date('N', $nexttime));
|
|
$this->assertEquals(0, date('i', $nexttime));
|
|
|
|
// Test monthly job.
|
|
$testclass = new scheduled_test_task();
|
|
$testclass->set_minute('32');
|
|
$testclass->set_hour('0');
|
|
$testclass->set_day('1');
|
|
|
|
$nexttime = $testclass->get_next_scheduled_time();
|
|
|
|
$this->assertEquals(32, date('i', $nexttime));
|
|
$this->assertEquals(0, date('G', $nexttime));
|
|
$this->assertEquals(1, date('j', $nexttime));
|
|
}
|
|
|
|
public function test_timezones() {
|
|
global $CFG, $USER;
|
|
|
|
// The timezones used in this test are chosen because they do not use DST - that would break the test.
|
|
$this->resetAfterTest();
|
|
|
|
$this->setTimezone('Asia/Kabul');
|
|
|
|
$testclass = new scheduled_test_task();
|
|
|
|
// Scheduled tasks should always use servertime - so this is 03:30 GMT.
|
|
$testclass->set_hour('1');
|
|
$testclass->set_minute('0');
|
|
|
|
// Next valid time should be 1am of the next day.
|
|
$nexttime = $testclass->get_next_scheduled_time();
|
|
|
|
// GMT+05:45.
|
|
$USER->timezone = 'Asia/Kathmandu';
|
|
$userdate = userdate($nexttime);
|
|
|
|
// Should be displayed in user timezone.
|
|
// I used http://www.timeanddate.com/worldclock/fixedtime.html?msg=Moodle+Test&iso=20160502T01&p1=113
|
|
// setting my location to Kathmandu to verify this time.
|
|
$this->assertStringContainsString('2:15 AM', \core_text::strtoupper($userdate));
|
|
}
|
|
|
|
public function test_reset_scheduled_tasks_for_component_customised(): void {
|
|
$this->resetAfterTest(true);
|
|
|
|
$tasks = manager::load_scheduled_tasks_for_component('moodle');
|
|
|
|
// Customise a task.
|
|
$task = reset($tasks);
|
|
$task->set_minute('1');
|
|
$task->set_hour('2');
|
|
$task->set_day('3');
|
|
$task->set_month('4');
|
|
$task->set_day_of_week('5');
|
|
$task->set_customised('1');
|
|
manager::configure_scheduled_task($task);
|
|
|
|
// Now call reset.
|
|
manager::reset_scheduled_tasks_for_component('moodle');
|
|
|
|
// Fetch the task again.
|
|
$taskafterreset = manager::get_scheduled_task(get_class($task));
|
|
|
|
// The task should still be the same as the customised.
|
|
$this->assertTaskEquals($task, $taskafterreset);
|
|
}
|
|
|
|
public function test_reset_scheduled_tasks_for_component_deleted(): void {
|
|
global $DB;
|
|
$this->resetAfterTest(true);
|
|
|
|
// Delete a task to simulate the fact that its new.
|
|
$tasklist = manager::load_scheduled_tasks_for_component('moodle');
|
|
|
|
// Note: This test must use a task which does not use any random values.
|
|
$task = manager::get_scheduled_task(session_cleanup_task::class);
|
|
|
|
$DB->delete_records('task_scheduled', array('classname' => '\\' . trim(get_class($task), '\\')));
|
|
$this->assertFalse(manager::get_scheduled_task(session_cleanup_task::class));
|
|
|
|
// Now call reset on all the tasks.
|
|
manager::reset_scheduled_tasks_for_component('moodle');
|
|
|
|
// Assert that the second task was added back.
|
|
$taskafterreset = manager::get_scheduled_task(session_cleanup_task::class);
|
|
$this->assertNotFalse($taskafterreset);
|
|
|
|
$this->assertTaskEquals($task, $taskafterreset);
|
|
$this->assertCount(count($tasklist), manager::load_scheduled_tasks_for_component('moodle'));
|
|
}
|
|
|
|
public function test_reset_scheduled_tasks_for_component_changed_in_source(): void {
|
|
$this->resetAfterTest(true);
|
|
|
|
// Delete a task to simulate the fact that its new.
|
|
// Note: This test must use a task which does not use any random values.
|
|
$task = manager::get_scheduled_task(session_cleanup_task::class);
|
|
|
|
// Get a copy of the task before maing changes for later comparison.
|
|
$taskbeforechange = manager::get_scheduled_task(session_cleanup_task::class);
|
|
|
|
// Edit a task to simulate a change in its definition (as if it was not customised).
|
|
$task->set_minute('1');
|
|
$task->set_hour('2');
|
|
$task->set_day('3');
|
|
$task->set_month('4');
|
|
$task->set_day_of_week('5');
|
|
manager::configure_scheduled_task($task);
|
|
|
|
// Fetch the task out for comparison.
|
|
$taskafterchange = manager::get_scheduled_task(session_cleanup_task::class);
|
|
|
|
// The task should now be different to the original.
|
|
$this->assertTaskNotEquals($taskbeforechange, $taskafterchange);
|
|
|
|
// Now call reset.
|
|
manager::reset_scheduled_tasks_for_component('moodle');
|
|
|
|
// Fetch the task again.
|
|
$taskafterreset = manager::get_scheduled_task(session_cleanup_task::class);
|
|
|
|
// The task should now be the same as the original.
|
|
$this->assertTaskEquals($taskbeforechange, $taskafterreset);
|
|
}
|
|
|
|
/**
|
|
* Tests that the reset function deletes old tasks.
|
|
*/
|
|
public function test_reset_scheduled_tasks_for_component_delete() {
|
|
global $DB;
|
|
$this->resetAfterTest(true);
|
|
|
|
$count = $DB->count_records('task_scheduled', array('component' => 'moodle'));
|
|
$allcount = $DB->count_records('task_scheduled');
|
|
|
|
$task = new scheduled_test_task();
|
|
$task->set_component('moodle');
|
|
$record = manager::record_from_scheduled_task($task);
|
|
$DB->insert_record('task_scheduled', $record);
|
|
$this->assertTrue($DB->record_exists('task_scheduled', array('classname' => '\core\task\scheduled_test_task',
|
|
'component' => 'moodle')));
|
|
|
|
$task = new scheduled_test2_task();
|
|
$task->set_component('moodle');
|
|
$record = manager::record_from_scheduled_task($task);
|
|
$DB->insert_record('task_scheduled', $record);
|
|
$this->assertTrue($DB->record_exists('task_scheduled', array('classname' => '\core\task\scheduled_test2_task',
|
|
'component' => 'moodle')));
|
|
|
|
$aftercount = $DB->count_records('task_scheduled', array('component' => 'moodle'));
|
|
$afterallcount = $DB->count_records('task_scheduled');
|
|
|
|
$this->assertEquals($count + 2, $aftercount);
|
|
$this->assertEquals($allcount + 2, $afterallcount);
|
|
|
|
// Now check that the right things were deleted.
|
|
manager::reset_scheduled_tasks_for_component('moodle');
|
|
|
|
$this->assertEquals($count, $DB->count_records('task_scheduled', array('component' => 'moodle')));
|
|
$this->assertEquals($allcount, $DB->count_records('task_scheduled'));
|
|
$this->assertFalse($DB->record_exists('task_scheduled', array('classname' => '\core\task\scheduled_test2_task',
|
|
'component' => 'moodle')));
|
|
$this->assertFalse($DB->record_exists('task_scheduled', array('classname' => '\core\task\scheduled_test_task',
|
|
'component' => 'moodle')));
|
|
}
|
|
|
|
public function test_get_next_scheduled_task() {
|
|
global $DB;
|
|
|
|
$this->resetAfterTest(true);
|
|
// Delete all existing scheduled tasks.
|
|
$DB->delete_records('task_scheduled');
|
|
// Add a scheduled task.
|
|
|
|
// A task that runs once per hour.
|
|
$record = new \stdClass();
|
|
$record->blocking = true;
|
|
$record->minute = '0';
|
|
$record->hour = '0';
|
|
$record->dayofweek = '*';
|
|
$record->day = '*';
|
|
$record->month = '*';
|
|
$record->component = 'test_scheduled_task';
|
|
$record->classname = '\core\task\scheduled_test_task';
|
|
|
|
$DB->insert_record('task_scheduled', $record);
|
|
// And another one to test failures.
|
|
$record->classname = '\core\task\scheduled_test2_task';
|
|
$DB->insert_record('task_scheduled', $record);
|
|
// And disabled test.
|
|
$record->classname = '\core\task\scheduled_test3_task';
|
|
$record->disabled = 1;
|
|
$DB->insert_record('task_scheduled', $record);
|
|
|
|
$now = time();
|
|
|
|
// Should get handed the first task.
|
|
$task = manager::get_next_scheduled_task($now);
|
|
$this->assertInstanceOf('\core\task\scheduled_test_task', $task);
|
|
$task->execute();
|
|
|
|
manager::scheduled_task_complete($task);
|
|
// Should get handed the second task.
|
|
$task = manager::get_next_scheduled_task($now);
|
|
$this->assertInstanceOf('\core\task\scheduled_test2_task', $task);
|
|
$task->execute();
|
|
|
|
manager::scheduled_task_failed($task);
|
|
// Should not get any task.
|
|
$task = manager::get_next_scheduled_task($now);
|
|
$this->assertNull($task);
|
|
|
|
// Should get the second task (retry after delay).
|
|
$task = manager::get_next_scheduled_task($now + 120);
|
|
$this->assertInstanceOf('\core\task\scheduled_test2_task', $task);
|
|
$task->execute();
|
|
|
|
manager::scheduled_task_complete($task);
|
|
|
|
// Should not get any task.
|
|
$task = manager::get_next_scheduled_task($now);
|
|
$this->assertNull($task);
|
|
|
|
// Check ordering.
|
|
$DB->delete_records('task_scheduled');
|
|
$record->lastruntime = 2;
|
|
$record->disabled = 0;
|
|
$record->classname = '\core\task\scheduled_test_task';
|
|
$DB->insert_record('task_scheduled', $record);
|
|
|
|
$record->lastruntime = 1;
|
|
$record->classname = '\core\task\scheduled_test2_task';
|
|
$DB->insert_record('task_scheduled', $record);
|
|
|
|
// Should get handed the second task.
|
|
$task = manager::get_next_scheduled_task($now);
|
|
$this->assertInstanceOf('\core\task\scheduled_test2_task', $task);
|
|
$task->execute();
|
|
manager::scheduled_task_complete($task);
|
|
|
|
// Should get handed the first task.
|
|
$task = manager::get_next_scheduled_task($now);
|
|
$this->assertInstanceOf('\core\task\scheduled_test_task', $task);
|
|
$task->execute();
|
|
manager::scheduled_task_complete($task);
|
|
|
|
// Should not get any task.
|
|
$task = manager::get_next_scheduled_task($now);
|
|
$this->assertNull($task);
|
|
}
|
|
|
|
public function test_get_broken_scheduled_task() {
|
|
global $DB;
|
|
|
|
$this->resetAfterTest(true);
|
|
// Delete all existing scheduled tasks.
|
|
$DB->delete_records('task_scheduled');
|
|
// Add a scheduled task.
|
|
|
|
// A broken task that runs all the time.
|
|
$record = new \stdClass();
|
|
$record->blocking = true;
|
|
$record->minute = '*';
|
|
$record->hour = '*';
|
|
$record->dayofweek = '*';
|
|
$record->day = '*';
|
|
$record->month = '*';
|
|
$record->component = 'test_scheduled_task';
|
|
$record->classname = '\core\task\scheduled_test_task_broken';
|
|
|
|
$DB->insert_record('task_scheduled', $record);
|
|
|
|
$now = time();
|
|
// Should not get any task.
|
|
$task = manager::get_next_scheduled_task($now);
|
|
$this->assertDebuggingCalled();
|
|
$this->assertNull($task);
|
|
}
|
|
|
|
/**
|
|
* Tests the use of 'R' syntax in time fields of tasks to get
|
|
* tasks be configured with a non-uniform time.
|
|
*/
|
|
public function test_random_time_specification() {
|
|
|
|
// Testing non-deterministic things in a unit test is not really
|
|
// wise, so we just test the values have changed within allowed bounds.
|
|
$testclass = new scheduled_test_task();
|
|
|
|
// The test task defaults to '*'.
|
|
$this->assertIsString($testclass->get_minute());
|
|
$this->assertIsString($testclass->get_hour());
|
|
|
|
// Set a random value.
|
|
$testclass->set_minute('R');
|
|
$testclass->set_hour('R');
|
|
$testclass->set_day_of_week('R');
|
|
|
|
// Verify the minute has changed within allowed bounds.
|
|
$minute = $testclass->get_minute();
|
|
$this->assertIsInt($minute);
|
|
$this->assertGreaterThanOrEqual(0, $minute);
|
|
$this->assertLessThanOrEqual(59, $minute);
|
|
|
|
// Verify the hour has changed within allowed bounds.
|
|
$hour = $testclass->get_hour();
|
|
$this->assertIsInt($hour);
|
|
$this->assertGreaterThanOrEqual(0, $hour);
|
|
$this->assertLessThanOrEqual(23, $hour);
|
|
|
|
// Verify the dayofweek has changed within allowed bounds.
|
|
$dayofweek = $testclass->get_day_of_week();
|
|
$this->assertIsInt($dayofweek);
|
|
$this->assertGreaterThanOrEqual(0, $dayofweek);
|
|
$this->assertLessThanOrEqual(6, $dayofweek);
|
|
}
|
|
|
|
/**
|
|
* Test that the file_temp_cleanup_task removes directories and
|
|
* files as expected.
|
|
*/
|
|
public function test_file_temp_cleanup_task() {
|
|
global $CFG;
|
|
$backuptempdir = make_backup_temp_directory('');
|
|
|
|
// Create directories.
|
|
$dir = $backuptempdir . DIRECTORY_SEPARATOR . 'backup01' . DIRECTORY_SEPARATOR . 'courses';
|
|
mkdir($dir, 0777, true);
|
|
|
|
// Create files to be checked and then deleted.
|
|
$file01 = $dir . DIRECTORY_SEPARATOR . 'sections.xml';
|
|
file_put_contents($file01, 'test data 001');
|
|
$file02 = $dir . DIRECTORY_SEPARATOR . 'modules.xml';
|
|
file_put_contents($file02, 'test data 002');
|
|
// Change the time modified for the first file, to a time that will be deleted by the task (greater than seven days).
|
|
touch($file01, time() - (8 * 24 * 3600));
|
|
|
|
$task = manager::get_scheduled_task('\\core\\task\\file_temp_cleanup_task');
|
|
$this->assertInstanceOf('\core\task\file_temp_cleanup_task', $task);
|
|
$task->execute();
|
|
|
|
// Scan the directory. Only modules.xml should be left.
|
|
$filesarray = scandir($dir);
|
|
$this->assertEquals('modules.xml', $filesarray[2]);
|
|
$this->assertEquals(3, count($filesarray));
|
|
|
|
// Change the time modified on modules.xml.
|
|
touch($file02, time() - (8 * 24 * 3600));
|
|
// Change the time modified on the courses directory.
|
|
touch($backuptempdir . DIRECTORY_SEPARATOR . 'backup01' . DIRECTORY_SEPARATOR .
|
|
'courses', time() - (8 * 24 * 3600));
|
|
// Run the scheduled task to remove the file and directory.
|
|
$task->execute();
|
|
$filesarray = scandir($backuptempdir . DIRECTORY_SEPARATOR . 'backup01');
|
|
// There should only be two items in the array, '.' and '..'.
|
|
$this->assertEquals(2, count($filesarray));
|
|
|
|
// Change the time modified on all of the files and directories.
|
|
$dir = new \RecursiveDirectoryIterator($CFG->tempdir);
|
|
// Show all child nodes prior to their parent.
|
|
$iter = new \RecursiveIteratorIterator($dir, \RecursiveIteratorIterator::CHILD_FIRST);
|
|
|
|
for ($iter->rewind(); $iter->valid(); $iter->next()) {
|
|
if ($iter->isDir() && !$iter->isDot()) {
|
|
$node = $iter->getRealPath();
|
|
touch($node, time() - (8 * 24 * 3600));
|
|
}
|
|
}
|
|
|
|
// Run the scheduled task again to remove all of the files and directories.
|
|
$task->execute();
|
|
$filesarray = scandir($CFG->tempdir);
|
|
// All of the files and directories should be deleted.
|
|
// There should only be three items in the array, '.', '..' and '.htaccess'.
|
|
$this->assertEquals([ '.', '..', '.htaccess' ], $filesarray);
|
|
}
|
|
|
|
/**
|
|
* Test that the function to clear the fail delay from a task works correctly.
|
|
*/
|
|
public function test_clear_fail_delay() {
|
|
|
|
$this->resetAfterTest();
|
|
|
|
// Get an example task to use for testing. Task is set to run every minute by default.
|
|
$taskname = '\core\task\send_new_user_passwords_task';
|
|
|
|
// Pretend task started running and then failed 3 times.
|
|
$before = time();
|
|
$cronlockfactory = \core\lock\lock_config::get_lock_factory('cron');
|
|
for ($i = 0; $i < 3; $i ++) {
|
|
$task = manager::get_scheduled_task($taskname);
|
|
$lock = $cronlockfactory->get_lock('\\' . get_class($task), 10);
|
|
$task->set_lock($lock);
|
|
manager::scheduled_task_failed($task);
|
|
}
|
|
|
|
// Confirm task is now delayed by several minutes.
|
|
$task = manager::get_scheduled_task($taskname);
|
|
$this->assertEquals(240, $task->get_fail_delay());
|
|
$this->assertGreaterThan($before + 230, $task->get_next_run_time());
|
|
|
|
// Clear the fail delay and re-get the task.
|
|
manager::clear_fail_delay($task);
|
|
$task = manager::get_scheduled_task($taskname);
|
|
|
|
// There should be no delay and it should run within the next minute.
|
|
$this->assertEquals(0, $task->get_fail_delay());
|
|
$this->assertLessThan($before + 70, $task->get_next_run_time());
|
|
}
|
|
|
|
/**
|
|
* Data provider for test_scheduled_task_override_values.
|
|
*/
|
|
public static function provider_schedule_overrides(): array {
|
|
return array(
|
|
array(
|
|
'scheduled_tasks' => array(
|
|
'\core\task\scheduled_test_task' => array(
|
|
'schedule' => '10 13 1 2 4',
|
|
'disabled' => 0,
|
|
),
|
|
'\core\task\scheduled_test2_task' => array(
|
|
'schedule' => '* * * * *',
|
|
'disabled' => 1,
|
|
),
|
|
),
|
|
'task_full_classnames' => array(
|
|
'\core\task\scheduled_test_task',
|
|
'\core\task\scheduled_test2_task',
|
|
),
|
|
'expected' => array(
|
|
'\core\task\scheduled_test_task' => array(
|
|
'min' => '10',
|
|
'hour' => '13',
|
|
'day' => '1',
|
|
'month' => '2',
|
|
'week' => '4',
|
|
'disabled' => 0,
|
|
),
|
|
'\core\task\scheduled_test2_task' => array(
|
|
'min' => '*',
|
|
'hour' => '*',
|
|
'day' => '*',
|
|
'month' => '*',
|
|
'week' => '*',
|
|
'disabled' => 1,
|
|
),
|
|
)
|
|
),
|
|
array(
|
|
'scheduled_tasks' => array(
|
|
'\core\task\*' => array(
|
|
'schedule' => '1 2 3 4 5',
|
|
'disabled' => 0,
|
|
)
|
|
),
|
|
'task_full_classnames' => array(
|
|
'\core\task\scheduled_test_task',
|
|
'\core\task\scheduled_test2_task',
|
|
),
|
|
'expected' => array(
|
|
'\core\task\scheduled_test_task' => array(
|
|
'min' => '1',
|
|
'hour' => '2',
|
|
'day' => '3',
|
|
'month' => '4',
|
|
'week' => '5',
|
|
'disabled' => 0,
|
|
),
|
|
'\core\task\scheduled_test2_task' => array(
|
|
'min' => '1',
|
|
'hour' => '2',
|
|
'day' => '3',
|
|
'month' => '4',
|
|
'week' => '5',
|
|
'disabled' => 0,
|
|
),
|
|
)
|
|
)
|
|
);
|
|
}
|
|
|
|
|
|
/**
|
|
* Test to ensure scheduled tasks are updated by values set in config.
|
|
*
|
|
* @param array $overrides
|
|
* @param array $tasks
|
|
* @param array $expected
|
|
* @dataProvider provider_schedule_overrides
|
|
*/
|
|
public function test_scheduled_task_override_values(array $overrides, array $tasks, array $expected): void {
|
|
global $CFG, $DB;
|
|
|
|
$this->resetAfterTest();
|
|
|
|
// Add overrides to the config.
|
|
$CFG->scheduled_tasks = $overrides;
|
|
|
|
// Set up test scheduled task record.
|
|
$record = new \stdClass();
|
|
$record->component = 'test_scheduled_task';
|
|
|
|
foreach ($tasks as $task) {
|
|
$record->classname = $task;
|
|
$DB->insert_record('task_scheduled', $record);
|
|
|
|
$scheduledtask = manager::get_scheduled_task($task);
|
|
$expectedresults = $expected[$task];
|
|
|
|
// Check that the task is actually overridden.
|
|
$this->assertTrue($scheduledtask->is_overridden(), 'Is overridden');
|
|
|
|
// Check minute is correct.
|
|
$this->assertEquals($expectedresults['min'], $scheduledtask->get_minute(), 'Minute check');
|
|
|
|
// Check day is correct.
|
|
$this->assertEquals($expectedresults['day'], $scheduledtask->get_day(), 'Day check');
|
|
|
|
// Check hour is correct.
|
|
$this->assertEquals($expectedresults['hour'], $scheduledtask->get_hour(), 'Hour check');
|
|
|
|
// Check week is correct.
|
|
$this->assertEquals($expectedresults['week'], $scheduledtask->get_day_of_week(), 'Day of week check');
|
|
|
|
// Check week is correct.
|
|
$this->assertEquals($expectedresults['month'], $scheduledtask->get_month(), 'Month check');
|
|
|
|
// Check to see if the task is disabled.
|
|
$this->assertEquals($expectedresults['disabled'], $scheduledtask->get_disabled(), 'Disabled check');
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Check that an overridden task is sent to be processed.
|
|
*/
|
|
public function test_scheduled_task_overridden_task_can_run(): void {
|
|
global $CFG, $DB;
|
|
|
|
$this->resetAfterTest();
|
|
|
|
// Delete all existing scheduled tasks.
|
|
$DB->delete_records('task_scheduled');
|
|
|
|
// Add overrides to the config.
|
|
$CFG->scheduled_tasks = [
|
|
'\core\task\scheduled_test_task' => [
|
|
'disabled' => 1
|
|
],
|
|
'\core\task\scheduled_test2_task' => [
|
|
'disabled' => 0
|
|
],
|
|
];
|
|
|
|
// A task that runs once per hour.
|
|
$record = new \stdClass();
|
|
$record->component = 'test_scheduled_task';
|
|
$record->classname = '\core\task\scheduled_test_task';
|
|
$record->disabled = 0;
|
|
$DB->insert_record('task_scheduled', $record);
|
|
|
|
// And disabled test.
|
|
$record->classname = '\core\task\scheduled_test2_task';
|
|
$record->disabled = 1;
|
|
$DB->insert_record('task_scheduled', $record);
|
|
|
|
$now = time();
|
|
|
|
$scheduledtask = manager::get_next_scheduled_task($now);
|
|
$this->assertInstanceOf('\core\task\scheduled_test2_task', $scheduledtask);
|
|
$scheduledtask->execute();
|
|
manager::scheduled_task_complete($scheduledtask);
|
|
}
|
|
|
|
/**
|
|
* Assert that the specified tasks are equal.
|
|
*
|
|
* @param \core\task\task_base $task
|
|
* @param \core\task\task_base $comparisontask
|
|
*/
|
|
public function assertTaskEquals(task_base $task, task_base $comparisontask): void {
|
|
// Convert both to an object.
|
|
$task = manager::record_from_scheduled_task($task);
|
|
$comparisontask = manager::record_from_scheduled_task($comparisontask);
|
|
|
|
// Reset the nextruntime field as it is intentionally dynamic.
|
|
$task->nextruntime = null;
|
|
$comparisontask->nextruntime = null;
|
|
|
|
$args = array_merge(
|
|
[
|
|
$task,
|
|
$comparisontask,
|
|
],
|
|
array_slice(func_get_args(), 2)
|
|
);
|
|
|
|
call_user_func_array([$this, 'assertEquals'], $args);
|
|
}
|
|
|
|
/**
|
|
* Assert that the specified tasks are not equal.
|
|
*
|
|
* @param \core\task\task_base $task
|
|
* @param \core\task\task_base $comparisontask
|
|
*/
|
|
public function assertTaskNotEquals(task_base $task, task_base $comparisontask): void {
|
|
// Convert both to an object.
|
|
$task = manager::record_from_scheduled_task($task);
|
|
$comparisontask = manager::record_from_scheduled_task($comparisontask);
|
|
|
|
// Reset the nextruntime field as it is intentionally dynamic.
|
|
$task->nextruntime = null;
|
|
$comparisontask->nextruntime = null;
|
|
|
|
$args = array_merge(
|
|
[
|
|
$task,
|
|
$comparisontask,
|
|
],
|
|
array_slice(func_get_args(), 2)
|
|
);
|
|
|
|
call_user_func_array([$this, 'assertNotEquals'], $args);
|
|
}
|
|
|
|
/**
|
|
* Assert that the lastruntime column holds an original value after a scheduled task is reset.
|
|
*/
|
|
public function test_reset_scheduled_tasks_for_component_keeps_original_lastruntime(): void {
|
|
global $DB;
|
|
$this->resetAfterTest(true);
|
|
|
|
// Set lastruntime for the scheduled task.
|
|
$DB->set_field('task_scheduled', 'lastruntime', 123456789, ['classname' => '\core\task\session_cleanup_task']);
|
|
|
|
// Reset the task.
|
|
manager::reset_scheduled_tasks_for_component('moodle');
|
|
|
|
// Fetch the task again.
|
|
$taskafterreset = manager::get_scheduled_task(session_cleanup_task::class);
|
|
|
|
// Confirm, that lastruntime is still in place.
|
|
$this->assertEquals(123456789, $taskafterreset->get_last_run_time());
|
|
}
|
|
|
|
/**
|
|
* Data provider for {@see test_is_component_enabled}
|
|
*
|
|
* @return array[]
|
|
*/
|
|
public function is_component_enabled_provider(): array {
|
|
return [
|
|
'Enabled component' => ['auth_cas', true],
|
|
'Disabled component' => ['auth_ldap', false],
|
|
'Invalid component' => ['auth_invalid', false],
|
|
];
|
|
}
|
|
|
|
/**
|
|
* Tests whether tasks belonging to components consider the component to be enabled
|
|
*
|
|
* @param string $component
|
|
* @param bool $expected
|
|
*
|
|
* @dataProvider is_component_enabled_provider
|
|
*/
|
|
public function test_is_component_enabled(string $component, bool $expected): void {
|
|
$this->resetAfterTest();
|
|
|
|
// Set cas as the only enabled auth component.
|
|
set_config('auth', 'cas');
|
|
|
|
$task = new scheduled_test_task();
|
|
$task->set_component($component);
|
|
|
|
$this->assertEquals($expected, $task->is_component_enabled());
|
|
}
|
|
|
|
/**
|
|
* Test whether tasks belonging to core components considers the component to be enabled
|
|
*/
|
|
public function test_is_component_enabled_core(): void {
|
|
$task = new scheduled_test_task();
|
|
$this->assertTrue($task->is_component_enabled());
|
|
}
|
|
}
|