[ Index ] |
PHP Cross Reference of Unnamed Project |
[Summary view] [Print] [Text view]
1 <?php 2 // This file is part of Moodle - http://moodle.org/ 3 // 4 // Moodle is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // Moodle is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU General Public License for more details. 13 // 14 // You should have received a copy of the GNU General Public License 15 // along with Moodle. If not, see <http://www.gnu.org/licenses/>. 16 17 /** 18 * This file contains the unittests for scheduled tasks. 19 * 20 * @package core 21 * @category phpunit 22 * @copyright 2013 Damyon Wiese 23 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 24 */ 25 26 defined('MOODLE_INTERNAL') || die(); 27 require_once (__DIR__ . '/fixtures/task_fixtures.php'); 28 29 /** 30 * Test class for scheduled task. 31 * 32 * @package core 33 * @category task 34 * @copyright 2013 Damyon Wiese 35 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 36 */ 37 class core_scheduled_task_testcase extends advanced_testcase { 38 39 /** 40 * Test the cron scheduling method 41 */ 42 public function test_eval_cron_field() { 43 $testclass = new \core\task\scheduled_test_task(); 44 45 $this->assertEquals(20, count($testclass->eval_cron_field('*/3', 0, 59))); 46 $this->assertEquals(31, count($testclass->eval_cron_field('1,*/2', 0, 59))); 47 $this->assertEquals(15, count($testclass->eval_cron_field('1-10,5-15', 0, 59))); 48 $this->assertEquals(13, count($testclass->eval_cron_field('1-10,5-15/2', 0, 59))); 49 $this->assertEquals(3, count($testclass->eval_cron_field('1,2,3,1,2,3', 0, 59))); 50 $this->assertEquals(1, count($testclass->eval_cron_field('-1,10,80', 0, 59))); 51 } 52 53 public function test_get_next_scheduled_time() { 54 global $CFG; 55 $this->resetAfterTest(); 56 57 $this->setTimezone('Europe/London'); 58 59 // Test job run at 1 am. 60 $testclass = new \core\task\scheduled_test_task(); 61 62 // All fields default to '*'. 63 $testclass->set_hour('1'); 64 $testclass->set_minute('0'); 65 // Next valid time should be 1am of the next day. 66 $nexttime = $testclass->get_next_scheduled_time(); 67 68 $oneamdate = new DateTime('now', new DateTimeZone('Europe/London')); 69 $oneamdate->setTime(1, 0, 0); 70 // Make it 1 am tomorrow if the time is after 1am. 71 if ($oneamdate->getTimestamp() < time()) { 72 $oneamdate->add(new DateInterval('P1D')); 73 } 74 $oneam = $oneamdate->getTimestamp(); 75 76 $this->assertEquals($oneam, $nexttime, 'Next scheduled time is 1am.'); 77 78 // Disabled flag does not affect next time. 79 $testclass->set_disabled(true); 80 $nexttime = $testclass->get_next_scheduled_time(); 81 $this->assertEquals($oneam, $nexttime, 'Next scheduled time is 1am.'); 82 83 // Now test for job run every 10 minutes. 84 $testclass = new \core\task\scheduled_test_task(); 85 86 // All fields default to '*'. 87 $testclass->set_minute('*/10'); 88 // Next valid time should be next 10 minute boundary. 89 $nexttime = $testclass->get_next_scheduled_time(); 90 91 $minutes = ((intval(date('i') / 10))+1) * 10; 92 $nexttenminutes = mktime(date('H'), $minutes, 0); 93 94 $this->assertEquals($nexttenminutes, $nexttime, 'Next scheduled time is in 10 minutes.'); 95 96 // Disabled flag does not affect next time. 97 $testclass->set_disabled(true); 98 $nexttime = $testclass->get_next_scheduled_time(); 99 $this->assertEquals($nexttenminutes, $nexttime, 'Next scheduled time is in 10 minutes.'); 100 101 // Test hourly job executed on Sundays only. 102 $testclass = new \core\task\scheduled_test_task(); 103 $testclass->set_minute('0'); 104 $testclass->set_day_of_week('7'); 105 106 $nexttime = $testclass->get_next_scheduled_time(); 107 108 $this->assertEquals(7, date('N', $nexttime)); 109 $this->assertEquals(0, date('i', $nexttime)); 110 111 // Test monthly job 112 $testclass = new \core\task\scheduled_test_task(); 113 $testclass->set_minute('32'); 114 $testclass->set_hour('0'); 115 $testclass->set_day('1'); 116 117 $nexttime = $testclass->get_next_scheduled_time(); 118 119 $this->assertEquals(32, date('i', $nexttime)); 120 $this->assertEquals(0, date('G', $nexttime)); 121 $this->assertEquals(1, date('j', $nexttime)); 122 } 123 124 public function test_timezones() { 125 global $CFG, $USER; 126 127 // The timezones used in this test are chosen because they do not use DST - that would break the test. 128 $this->resetAfterTest(); 129 130 $this->setTimezone('Asia/Kabul'); 131 132 $testclass = new \core\task\scheduled_test_task(); 133 134 // Scheduled tasks should always use servertime - so this is 03:30 GMT. 135 $testclass->set_hour('1'); 136 $testclass->set_minute('0'); 137 138 // Next valid time should be 1am of the next day. 139 $nexttime = $testclass->get_next_scheduled_time(); 140 141 // GMT+05:45. 142 $USER->timezone = 'Asia/Kathmandu'; 143 $userdate = userdate($nexttime); 144 145 // Should be displayed in user timezone. 146 // I used http://www.timeanddate.com/worldclock/fixedtime.html?msg=Moodle+Test&iso=20160502T01&p1=113 147 // setting my location to Kathmandu to verify this time. 148 $this->assertContains('2:15 AM', core_text::strtoupper($userdate)); 149 } 150 151 public function test_reset_scheduled_tasks_for_component() { 152 global $DB; 153 154 $this->resetAfterTest(true); 155 // Remember the defaults. 156 $defaulttasks = \core\task\manager::load_scheduled_tasks_for_component('moodle'); 157 $initcount = count($defaulttasks); 158 // Customise a task. 159 $firsttask = reset($defaulttasks); 160 $firsttask->set_minute('1'); 161 $firsttask->set_hour('2'); 162 $firsttask->set_month('3'); 163 $firsttask->set_day_of_week('4'); 164 $firsttask->set_day('5'); 165 $firsttask->set_customised('1'); 166 \core\task\manager::configure_scheduled_task($firsttask); 167 $firsttaskrecord = \core\task\manager::record_from_scheduled_task($firsttask); 168 // We reset this field, because we do not want to compare it. 169 $firsttaskrecord->nextruntime = '0'; 170 171 // Delete a task to simulate the fact that its new. 172 $secondtask = next($defaulttasks); 173 $DB->delete_records('task_scheduled', array('classname' => '\\' . trim(get_class($secondtask), '\\'))); 174 $this->assertFalse(\core\task\manager::get_scheduled_task(get_class($secondtask))); 175 176 // Edit a task to simulate a change in its definition (as if it was not customised). 177 $thirdtask = next($defaulttasks); 178 $thirdtask->set_minute('1'); 179 $thirdtask->set_hour('2'); 180 $thirdtask->set_month('3'); 181 $thirdtask->set_day_of_week('4'); 182 $thirdtask->set_day('5'); 183 $thirdtaskbefore = \core\task\manager::get_scheduled_task(get_class($thirdtask)); 184 $thirdtaskbefore->set_next_run_time(null); // Ignore this value when comparing. 185 \core\task\manager::configure_scheduled_task($thirdtask); 186 $thirdtask = \core\task\manager::get_scheduled_task(get_class($thirdtask)); 187 $thirdtask->set_next_run_time(null); // Ignore this value when comparing. 188 $this->assertNotEquals($thirdtaskbefore, $thirdtask); 189 190 // Now call reset on all the tasks. 191 \core\task\manager::reset_scheduled_tasks_for_component('moodle'); 192 193 // Load the tasks again. 194 $defaulttasks = \core\task\manager::load_scheduled_tasks_for_component('moodle'); 195 $finalcount = count($defaulttasks); 196 // Compare the first task. 197 $newfirsttask = reset($defaulttasks); 198 $newfirsttaskrecord = \core\task\manager::record_from_scheduled_task($newfirsttask); 199 // We reset this field, because we do not want to compare it. 200 $newfirsttaskrecord->nextruntime = '0'; 201 202 // Assert a customised task was not altered by reset. 203 $this->assertEquals($firsttaskrecord, $newfirsttaskrecord); 204 205 // Assert that the second task was added back. 206 $secondtaskafter = \core\task\manager::get_scheduled_task(get_class($secondtask)); 207 $secondtaskafter->set_next_run_time(null); // Do not compare the nextruntime. 208 $secondtask->set_next_run_time(null); 209 $this->assertEquals($secondtask, $secondtaskafter); 210 211 // Assert that the third task edits were overridden. 212 $thirdtaskafter = \core\task\manager::get_scheduled_task(get_class($thirdtask)); 213 $thirdtaskafter->set_next_run_time(null); 214 $this->assertEquals($thirdtaskbefore, $thirdtaskafter); 215 216 // Assert we have the same number of tasks. 217 $this->assertEquals($initcount, $finalcount); 218 } 219 220 /** 221 * Tests that the reset function deletes old tasks. 222 */ 223 public function test_reset_scheduled_tasks_for_component_delete() { 224 global $DB; 225 $this->resetAfterTest(true); 226 227 $count = $DB->count_records('task_scheduled', array('component' => 'moodle')); 228 $allcount = $DB->count_records('task_scheduled'); 229 230 $task = new \core\task\scheduled_test_task(); 231 $task->set_component('moodle'); 232 $record = \core\task\manager::record_from_scheduled_task($task); 233 $DB->insert_record('task_scheduled', $record); 234 $this->assertTrue($DB->record_exists('task_scheduled', array('classname' => '\core\task\scheduled_test_task', 235 'component' => 'moodle'))); 236 237 $task = new \core\task\scheduled_test2_task(); 238 $task->set_component('moodle'); 239 $record = \core\task\manager::record_from_scheduled_task($task); 240 $DB->insert_record('task_scheduled', $record); 241 $this->assertTrue($DB->record_exists('task_scheduled', array('classname' => '\core\task\scheduled_test2_task', 242 'component' => 'moodle'))); 243 244 $aftercount = $DB->count_records('task_scheduled', array('component' => 'moodle')); 245 $afterallcount = $DB->count_records('task_scheduled'); 246 247 $this->assertEquals($count + 2, $aftercount); 248 $this->assertEquals($allcount + 2, $afterallcount); 249 250 // Now check that the right things were deleted. 251 \core\task\manager::reset_scheduled_tasks_for_component('moodle'); 252 253 $this->assertEquals($count, $DB->count_records('task_scheduled', array('component' => 'moodle'))); 254 $this->assertEquals($allcount, $DB->count_records('task_scheduled')); 255 $this->assertFalse($DB->record_exists('task_scheduled', array('classname' => '\core\task\scheduled_test2_task', 256 'component' => 'moodle'))); 257 $this->assertFalse($DB->record_exists('task_scheduled', array('classname' => '\core\task\scheduled_test_task', 258 'component' => 'moodle'))); 259 } 260 261 public function test_get_next_scheduled_task() { 262 global $DB; 263 264 $this->resetAfterTest(true); 265 // Delete all existing scheduled tasks. 266 $DB->delete_records('task_scheduled'); 267 // Add a scheduled task. 268 269 // A task that runs once per hour. 270 $record = new stdClass(); 271 $record->blocking = true; 272 $record->minute = '0'; 273 $record->hour = '0'; 274 $record->dayofweek = '*'; 275 $record->day = '*'; 276 $record->month = '*'; 277 $record->component = 'test_scheduled_task'; 278 $record->classname = '\core\task\scheduled_test_task'; 279 280 $DB->insert_record('task_scheduled', $record); 281 // And another one to test failures. 282 $record->classname = '\core\task\scheduled_test2_task'; 283 $DB->insert_record('task_scheduled', $record); 284 // And disabled test. 285 $record->classname = '\core\task\scheduled_test3_task'; 286 $record->disabled = 1; 287 $DB->insert_record('task_scheduled', $record); 288 289 $now = time(); 290 291 // Should get handed the first task. 292 $task = \core\task\manager::get_next_scheduled_task($now); 293 $this->assertInstanceOf('\core\task\scheduled_test_task', $task); 294 $task->execute(); 295 296 \core\task\manager::scheduled_task_complete($task); 297 // Should get handed the second task. 298 $task = \core\task\manager::get_next_scheduled_task($now); 299 $this->assertInstanceOf('\core\task\scheduled_test2_task', $task); 300 $task->execute(); 301 302 \core\task\manager::scheduled_task_failed($task); 303 // Should not get any task. 304 $task = \core\task\manager::get_next_scheduled_task($now); 305 $this->assertNull($task); 306 307 // Should get the second task (retry after delay). 308 $task = \core\task\manager::get_next_scheduled_task($now + 120); 309 $this->assertInstanceOf('\core\task\scheduled_test2_task', $task); 310 $task->execute(); 311 312 \core\task\manager::scheduled_task_complete($task); 313 314 // Should not get any task. 315 $task = \core\task\manager::get_next_scheduled_task($now); 316 $this->assertNull($task); 317 318 // Check ordering. 319 $DB->delete_records('task_scheduled'); 320 $record->lastruntime = 2; 321 $record->disabled = 0; 322 $record->classname = '\core\task\scheduled_test_task'; 323 $DB->insert_record('task_scheduled', $record); 324 325 $record->lastruntime = 1; 326 $record->classname = '\core\task\scheduled_test2_task'; 327 $DB->insert_record('task_scheduled', $record); 328 329 // Should get handed the second task. 330 $task = \core\task\manager::get_next_scheduled_task($now); 331 $this->assertInstanceOf('\core\task\scheduled_test2_task', $task); 332 $task->execute(); 333 \core\task\manager::scheduled_task_complete($task); 334 335 // Should get handed the first task. 336 $task = \core\task\manager::get_next_scheduled_task($now); 337 $this->assertInstanceOf('\core\task\scheduled_test_task', $task); 338 $task->execute(); 339 \core\task\manager::scheduled_task_complete($task); 340 341 // Should not get any task. 342 $task = \core\task\manager::get_next_scheduled_task($now); 343 $this->assertNull($task); 344 } 345 346 public function test_get_broken_scheduled_task() { 347 global $DB; 348 349 $this->resetAfterTest(true); 350 // Delete all existing scheduled tasks. 351 $DB->delete_records('task_scheduled'); 352 // Add a scheduled task. 353 354 // A broken task that runs all the time. 355 $record = new stdClass(); 356 $record->blocking = true; 357 $record->minute = '*'; 358 $record->hour = '*'; 359 $record->dayofweek = '*'; 360 $record->day = '*'; 361 $record->month = '*'; 362 $record->component = 'test_scheduled_task'; 363 $record->classname = '\core\task\scheduled_test_task_broken'; 364 365 $DB->insert_record('task_scheduled', $record); 366 367 $now = time(); 368 // Should not get any task. 369 $task = \core\task\manager::get_next_scheduled_task($now); 370 $this->assertDebuggingCalled(); 371 $this->assertNull($task); 372 } 373 374 /** 375 * Tests the use of 'R' syntax in time fields of tasks to get 376 * tasks be configured with a non-uniform time. 377 */ 378 public function test_random_time_specification() { 379 380 // Testing non-deterministic things in a unit test is not really 381 // wise, so we just test the values have changed within allowed bounds. 382 $testclass = new \core\task\scheduled_test_task(); 383 384 // The test task defaults to '*'. 385 $this->assertInternalType('string', $testclass->get_minute()); 386 $this->assertInternalType('string', $testclass->get_hour()); 387 388 // Set a random value. 389 $testclass->set_minute('R'); 390 $testclass->set_hour('R'); 391 $testclass->set_day_of_week('R'); 392 393 // Verify the minute has changed within allowed bounds. 394 $minute = $testclass->get_minute(); 395 $this->assertInternalType('int', $minute); 396 $this->assertGreaterThanOrEqual(0, $minute); 397 $this->assertLessThanOrEqual(59, $minute); 398 399 // Verify the hour has changed within allowed bounds. 400 $hour = $testclass->get_hour(); 401 $this->assertInternalType('int', $hour); 402 $this->assertGreaterThanOrEqual(0, $hour); 403 $this->assertLessThanOrEqual(23, $hour); 404 405 // Verify the dayofweek has changed within allowed bounds. 406 $dayofweek = $testclass->get_day_of_week(); 407 $this->assertInternalType('int', $dayofweek); 408 $this->assertGreaterThanOrEqual(0, $dayofweek); 409 $this->assertLessThanOrEqual(6, $dayofweek); 410 } 411 412 /** 413 * Test that the file_temp_cleanup_task removes directories and 414 * files as expected. 415 */ 416 public function test_file_temp_cleanup_task() { 417 global $CFG; 418 419 // Create directories. 420 $dir = $CFG->tempdir . DIRECTORY_SEPARATOR . 'backup' . DIRECTORY_SEPARATOR . 'backup01' . DIRECTORY_SEPARATOR . 'courses'; 421 mkdir($dir, 0777, true); 422 423 // Create files to be checked and then deleted. 424 $file01 = $dir . DIRECTORY_SEPARATOR . 'sections.xml'; 425 file_put_contents($file01, 'test data 001'); 426 $file02 = $dir . DIRECTORY_SEPARATOR . 'modules.xml'; 427 file_put_contents($file02, 'test data 002'); 428 // Change the time modified for the first file, to a time that will be deleted by the task (greater than seven days). 429 touch($file01, time() - (8 * 24 * 3600)); 430 431 $task = \core\task\manager::get_scheduled_task('\\core\\task\\file_temp_cleanup_task'); 432 $this->assertInstanceOf('\core\task\file_temp_cleanup_task', $task); 433 $task->execute(); 434 435 // Scan the directory. Only modules.xml should be left. 436 $filesarray = scandir($dir); 437 $this->assertEquals('modules.xml', $filesarray[2]); 438 $this->assertEquals(3, count($filesarray)); 439 440 // Change the time modified on modules.xml. 441 touch($file02, time() - (8 * 24 * 3600)); 442 // Change the time modified on the courses directory. 443 touch($CFG->tempdir . DIRECTORY_SEPARATOR . 'backup' . DIRECTORY_SEPARATOR . 'backup01' . DIRECTORY_SEPARATOR . 444 'courses', time() - (8 * 24 * 3600)); 445 // Run the scheduled task to remove the file and directory. 446 $task->execute(); 447 $filesarray = scandir($CFG->tempdir . DIRECTORY_SEPARATOR . 'backup' . DIRECTORY_SEPARATOR . 'backup01'); 448 // There should only be two items in the array, '.' and '..'. 449 $this->assertEquals(2, count($filesarray)); 450 451 // Change the time modified on all of the files and directories. 452 $dir = new \RecursiveDirectoryIterator($CFG->tempdir); 453 // Show all child nodes prior to their parent. 454 $iter = new \RecursiveIteratorIterator($dir, \RecursiveIteratorIterator::CHILD_FIRST); 455 456 for ($iter->rewind(); $iter->valid(); $iter->next()) { 457 if ($iter->isDir() && !$iter->isDot()) { 458 $node = $iter->getRealPath(); 459 touch($node, time() - (8 * 24 * 3600)); 460 } 461 } 462 463 // Run the scheduled task again to remove all of the files and directories. 464 $task->execute(); 465 $filesarray = scandir($CFG->tempdir); 466 // All of the files and directories should be deleted. 467 // There should only be two items in the array, '.' and '..'. 468 $this->assertEquals(2, count($filesarray)); 469 } 470 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Thu Aug 11 10:00:09 2016 | Cross-referenced by PHPXref 0.7.1 |