Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 3.11.x will end 14 Nov 2022 (12 months plus 6 months extension).
  • Bug fixes for security issues in 3.11.x will end 13 Nov 2023 (18 months plus 12 months extension).
  • PHP version: minimum PHP 7.3.0 Note: minimum PHP version has increased since Moodle 3.10. PHP 7.4.x is supported too.

Differences Between: [Versions 311 and 400] [Versions 311 and 401] [Versions 311 and 402] [Versions 311 and 403]

   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  namespace core\task;
  18  
  19  defined('MOODLE_INTERNAL') || die();
  20  require_once (__DIR__ . '/../fixtures/task_fixtures.php');
  21  
  22  
  23  /**
  24   * Test class for adhoc tasks.
  25   *
  26   * @package core
  27   * @category test
  28   * @copyright 2013 Damyon Wiese
  29   * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  30   */
  31  class adhoc_task_test extends \advanced_testcase {
  32  
  33      /**
  34       * Test basic adhoc task execution.
  35       */
  36      public function test_get_next_adhoc_task_now() {
  37          $this->resetAfterTest(true);
  38  
  39          // Create an adhoc task.
  40          $task = new adhoc_test_task();
  41  
  42          // Queue it.
  43          manager::queue_adhoc_task($task);
  44  
  45          $now = time();
  46          // Get it from the scheduler.
  47          $task = manager::get_next_adhoc_task($now);
  48          $this->assertInstanceOf('\\core\\task\\adhoc_test_task', $task);
  49          $task->execute();
  50          manager::adhoc_task_complete($task);
  51      }
  52  
  53      /**
  54       * Test adhoc task failure retry backoff.
  55       */
  56      public function test_get_next_adhoc_task_fail_retry() {
  57          $this->resetAfterTest(true);
  58  
  59          // Create an adhoc task.
  60          $task = new adhoc_test_task();
  61          manager::queue_adhoc_task($task);
  62  
  63          $now = time();
  64  
  65          // Get it from the scheduler, execute it, and mark it as failed.
  66          $task = manager::get_next_adhoc_task($now);
  67          $task->execute();
  68          manager::adhoc_task_failed($task);
  69  
  70          // The task will not be returned immediately.
  71          $this->assertNull(manager::get_next_adhoc_task($now));
  72  
  73          // Should get the adhoc task (retry after delay).
  74          $task = manager::get_next_adhoc_task($now + 120);
  75          $this->assertInstanceOf('\\core\\task\\adhoc_test_task', $task);
  76          $task->execute();
  77  
  78          manager::adhoc_task_complete($task);
  79  
  80          // Should not get any task.
  81          $this->assertNull(manager::get_next_adhoc_task($now));
  82      }
  83  
  84      /**
  85       * Test future adhoc task execution.
  86       */
  87      public function test_get_next_adhoc_task_future() {
  88          $this->resetAfterTest(true);
  89  
  90          $now = time();
  91          // Create an adhoc task in future.
  92          $task = new adhoc_test_task();
  93          $task->set_next_run_time($now + 1000);
  94          manager::queue_adhoc_task($task);
  95  
  96          // Fetching the next task should not return anything.
  97          $this->assertNull(manager::get_next_adhoc_task($now));
  98  
  99          // Fetching in the future should return the task.
 100          $task = manager::get_next_adhoc_task($now + 1020);
 101          $this->assertInstanceOf('\\core\\task\\adhoc_test_task', $task);
 102          $task->execute();
 103          manager::adhoc_task_complete($task);
 104      }
 105  
 106      /**
 107       * Test queueing an adhoc task belonging to a component, where we set the task component accordingly
 108       */
 109      public function test_queue_adhoc_task_for_component(): void {
 110          $this->resetAfterTest();
 111  
 112          $task = new \mod_forum\task\refresh_forum_post_counts();
 113          $task->set_component('mod_test');
 114  
 115          manager::queue_adhoc_task($task);
 116          $this->assertDebuggingNotCalled();
 117      }
 118  
 119      /**
 120       * Test queueing an adhoc task belonging to a component, where we do not set the task component
 121       */
 122      public function test_queue_task_for_component_without_set_component(): void {
 123          $this->resetAfterTest();
 124  
 125          $task = new \mod_forum\task\refresh_forum_post_counts();
 126  
 127          manager::queue_adhoc_task($task);
 128          $this->assertDebuggingNotCalled();
 129  
 130          // Assert the missing component was set.
 131          $this->assertEquals('mod_forum', $task->get_component());
 132      }
 133  
 134      /**
 135       * Test queueing an adhoc task belonging to an invalid component, where we do not set the task component
 136       */
 137      public function test_queue_task_for_invalid_component_without_set_component(): void {
 138          $this->resetAfterTest();
 139  
 140          $task = new \mod_fake\task\adhoc_component_task();
 141  
 142          manager::queue_adhoc_task($task);
 143          $this->assertDebuggingCalled('Component not set and the class namespace does not match a valid component (mod_fake).');
 144      }
 145  
 146      /**
 147       * Test empty set of adhoc tasks
 148       */
 149      public function test_get_adhoc_tasks_empty_set() {
 150          $this->resetAfterTest(true);
 151  
 152          $this->assertEquals([], manager::get_adhoc_tasks('\\core\\task\\adhoc_test_task'));
 153      }
 154  
 155      /**
 156       * Test correct set of adhoc tasks is returned for class.
 157       */
 158      public function test_get_adhoc_tasks_result_set() {
 159          $this->resetAfterTest(true);
 160  
 161          for ($i = 0; $i < 3; $i++) {
 162              $task = new adhoc_test_task();
 163              manager::queue_adhoc_task($task);
 164          }
 165  
 166          for ($i = 0; $i < 3; $i++) {
 167              $task = new adhoc_test2_task();
 168              manager::queue_adhoc_task($task);
 169          }
 170  
 171          $adhoctests = manager::get_adhoc_tasks('\\core\\task\\adhoc_test_task');
 172          $adhoctest2s = manager::get_adhoc_tasks('\\core\\task\\adhoc_test2_task');
 173  
 174          $this->assertCount(3, $adhoctests);
 175          $this->assertCount(3, $adhoctest2s);
 176  
 177          foreach ($adhoctests as $task) {
 178              $this->assertInstanceOf('\\core\\task\\adhoc_test_task', $task);
 179          }
 180  
 181          foreach ($adhoctest2s as $task) {
 182              $this->assertInstanceOf('\\core\\task\\adhoc_test2_task', $task);
 183          }
 184      }
 185  
 186      /**
 187       * Ensure that the reschedule_or_queue_adhoc_task function will schedule a new task if no tasks exist.
 188       */
 189      public function test_reschedule_or_queue_adhoc_task_no_existing() {
 190          $this->resetAfterTest(true);
 191  
 192          // Schedule adhoc task.
 193          $task = new adhoc_test_task();
 194          $task->set_custom_data(['courseid' => 10]);
 195          manager::reschedule_or_queue_adhoc_task($task);
 196          $this->assertEquals(1, count(manager::get_adhoc_tasks('core\task\adhoc_test_task')));
 197      }
 198  
 199      /**
 200       * Ensure that the reschedule_or_queue_adhoc_task function will schedule a new task if a task for the same user does
 201       * not exist.
 202       */
 203      public function test_reschedule_or_queue_adhoc_task_different_user() {
 204          $this->resetAfterTest(true);
 205          $user = \core_user::get_user_by_username('admin');
 206  
 207          // Schedule adhoc task.
 208          $task = new adhoc_test_task();
 209          $task->set_custom_data(['courseid' => 10]);
 210          manager::reschedule_or_queue_adhoc_task($task);
 211  
 212          // Schedule adhoc task for a different user.
 213          $task = new adhoc_test_task();
 214          $task->set_custom_data(['courseid' => 10]);
 215          $task->set_userid($user->id);
 216          manager::reschedule_or_queue_adhoc_task($task);
 217  
 218          $this->assertEquals(2, count(manager::get_adhoc_tasks('core\task\adhoc_test_task')));
 219      }
 220  
 221      /**
 222       * Ensure that the reschedule_or_queue_adhoc_task function will schedule a new task if a task with different custom
 223       * data exists.
 224       */
 225      public function test_reschedule_or_queue_adhoc_task_different_data() {
 226          $this->resetAfterTest(true);
 227  
 228          // Schedule adhoc task.
 229          $task = new adhoc_test_task();
 230          $task->set_custom_data(['courseid' => 10]);
 231          manager::reschedule_or_queue_adhoc_task($task);
 232  
 233          // Schedule adhoc task for a different user.
 234          $task = new adhoc_test_task();
 235          $task->set_custom_data(['courseid' => 11]);
 236          manager::reschedule_or_queue_adhoc_task($task);
 237  
 238          $this->assertEquals(2, count(manager::get_adhoc_tasks('core\task\adhoc_test_task')));
 239      }
 240  
 241      /**
 242       * Ensure that the reschedule_or_queue_adhoc_task function will not make any change for matching data if no time was
 243       * specified.
 244       */
 245      public function test_reschedule_or_queue_adhoc_task_match_no_change() {
 246          $this->resetAfterTest(true);
 247  
 248          // Schedule adhoc task.
 249          $task = new adhoc_test_task();
 250          $task->set_custom_data(['courseid' => 10]);
 251          $task->set_next_run_time(time() + DAYSECS);
 252          manager::reschedule_or_queue_adhoc_task($task);
 253  
 254          $before = manager::get_adhoc_tasks('core\task\adhoc_test_task');
 255  
 256          // Schedule the task again but do not specify a time.
 257          $task = new adhoc_test_task();
 258          $task->set_custom_data(['courseid' => 10]);
 259          manager::reschedule_or_queue_adhoc_task($task);
 260  
 261          $this->assertEquals(1, count(manager::get_adhoc_tasks('core\task\adhoc_test_task')));
 262          $this->assertEquals($before, manager::get_adhoc_tasks('core\task\adhoc_test_task'));
 263      }
 264  
 265      /**
 266       * Ensure that the reschedule_or_queue_adhoc_task function will update the run time if there are planned changes.
 267       */
 268      public function test_reschedule_or_queue_adhoc_task_match_update_runtime() {
 269          $this->resetAfterTest(true);
 270          $initialruntime = time() + DAYSECS;
 271          $newruntime = time() + WEEKSECS;
 272  
 273          // Schedule adhoc task.
 274          $task = new adhoc_test_task();
 275          $task->set_custom_data(['courseid' => 10]);
 276          $task->set_next_run_time($initialruntime);
 277          manager::reschedule_or_queue_adhoc_task($task);
 278  
 279          $before = manager::get_adhoc_tasks('core\task\adhoc_test_task');
 280  
 281          // Schedule the task again.
 282          $task = new adhoc_test_task();
 283          $task->set_custom_data(['courseid' => 10]);
 284          $task->set_next_run_time($newruntime);
 285          manager::reschedule_or_queue_adhoc_task($task);
 286  
 287          $tasks = manager::get_adhoc_tasks('core\task\adhoc_test_task');
 288          $this->assertEquals(1, count($tasks));
 289          $this->assertNotEquals($before, $tasks);
 290          $firsttask = reset($tasks);
 291          $this->assertEquals($newruntime, $firsttask->get_next_run_time());
 292      }
 293  
 294      /**
 295       * Test queue_adhoc_task "if not scheduled".
 296       */
 297      public function test_queue_adhoc_task_if_not_scheduled() {
 298          $this->resetAfterTest(true);
 299          $user = \core_user::get_user_by_username('admin');
 300  
 301          // Schedule adhoc task.
 302          $task = new adhoc_test_task();
 303          $task->set_custom_data(array('courseid' => 10));
 304          $this->assertNotEmpty(manager::queue_adhoc_task($task, true));
 305          $this->assertEquals(1, count(manager::get_adhoc_tasks('core\task\adhoc_test_task')));
 306  
 307          // Schedule adhoc task with a user.
 308          $task = new adhoc_test_task();
 309          $task->set_custom_data(array('courseid' => 10));
 310          $task->set_userid($user->id);
 311          $this->assertNotEmpty(manager::queue_adhoc_task($task, true));
 312          $this->assertEquals(2, count(manager::get_adhoc_tasks('core\task\adhoc_test_task')));
 313  
 314          // Schedule same adhoc task with different custom data.
 315          $task = new adhoc_test_task();
 316          $task->set_custom_data(array('courseid' => 1));
 317          $this->assertNotEmpty(manager::queue_adhoc_task($task, true));
 318          $this->assertEquals(3, count(manager::get_adhoc_tasks('core\task\adhoc_test_task')));
 319  
 320          // Schedule same adhoc task with same custom data.
 321          $task = new adhoc_test_task();
 322          $task->set_custom_data(array('courseid' => 1));
 323          $this->assertEmpty(manager::queue_adhoc_task($task, true));
 324          $this->assertEquals(3, count(manager::get_adhoc_tasks('core\task\adhoc_test_task')));
 325  
 326          // Schedule same adhoc task with same custom data and a user.
 327          $task = new adhoc_test_task();
 328          $task->set_custom_data(array('courseid' => 1));
 329          $task->set_userid($user->id);
 330          $this->assertNotEmpty(manager::queue_adhoc_task($task, true));
 331          $this->assertEquals(4, count(manager::get_adhoc_tasks('core\task\adhoc_test_task')));
 332  
 333          // Schedule same adhoc task without custom data.
 334          // Note: This task was created earlier.
 335          $task = new adhoc_test_task();
 336          $this->assertNotEmpty(manager::queue_adhoc_task($task, true));
 337          $this->assertEquals(5, count(manager::get_adhoc_tasks('core\task\adhoc_test_task')));
 338  
 339          // Schedule same adhoc task without custom data (again).
 340          $task5 = new adhoc_test_task();
 341          $this->assertEmpty(manager::queue_adhoc_task($task5, true));
 342          $this->assertEquals(5, count(manager::get_adhoc_tasks('core\task\adhoc_test_task')));
 343  
 344          // Schedule same adhoc task without custom data but with a userid.
 345          $task6 = new adhoc_test_task();
 346          $user = \core_user::get_user_by_username('admin');
 347          $task6->set_userid($user->id);
 348          $this->assertNotEmpty(manager::queue_adhoc_task($task6, true));
 349          $this->assertEquals(6, count(manager::get_adhoc_tasks('core\task\adhoc_test_task')));
 350  
 351          // Schedule same adhoc task again without custom data but with a userid.
 352          $task6 = new adhoc_test_task();
 353          $user = \core_user::get_user_by_username('admin');
 354          $task6->set_userid($user->id);
 355          $this->assertEmpty(manager::queue_adhoc_task($task6, true));
 356          $this->assertEquals(6, count(manager::get_adhoc_tasks('core\task\adhoc_test_task')));
 357      }
 358  
 359      /**
 360       * Test that when no userid is specified, it returns empty from the DB
 361       * too.
 362       */
 363      public function test_adhoc_task_user_empty() {
 364          $this->resetAfterTest(true);
 365  
 366          // Create an adhoc task in future.
 367          $task = new adhoc_test_task();
 368          manager::queue_adhoc_task($task);
 369  
 370          // Get it back from the scheduler.
 371          $now = time();
 372          $task = manager::get_next_adhoc_task($now);
 373          manager::adhoc_task_complete($task);
 374  
 375          $this->assertEmpty($task->get_userid());
 376      }
 377  
 378      /**
 379       * Test that when a userid is specified, that userid is subsequently
 380       * returned.
 381       */
 382      public function test_adhoc_task_user_set() {
 383          $this->resetAfterTest(true);
 384  
 385          // Create an adhoc task in future.
 386          $task = new adhoc_test_task();
 387          $user = \core_user::get_user_by_username('admin');
 388          $task->set_userid($user->id);
 389          manager::queue_adhoc_task($task);
 390  
 391          // Get it back from the scheduler.
 392          $now = time();
 393          $task = manager::get_next_adhoc_task($now);
 394          manager::adhoc_task_complete($task);
 395  
 396          $this->assertEquals($user->id, $task->get_userid());
 397      }
 398  
 399      /**
 400       * Test get_concurrency_limit() method to return 0 by default.
 401       */
 402      public function test_get_concurrency_limit() {
 403          $this->resetAfterTest(true);
 404          $task = new adhoc_test_task();
 405          $concurrencylimit = $task->get_concurrency_limit();
 406          $this->assertEquals(0, $concurrencylimit);
 407      }
 408  
 409      /**
 410       * Test get_concurrency_limit() method to return a default value set in config.
 411       */
 412      public function test_get_concurrency_limit_default() {
 413          $this->resetAfterTest(true);
 414          set_config('task_concurrency_limit_default', 10);
 415          $task = new adhoc_test_task();
 416          $concurrencylimit = $task->get_concurrency_limit();
 417          $this->assertEquals(10, $concurrencylimit);
 418      }
 419  
 420      /**
 421       * Test get_concurrency_limit() method to return a value for specific task class.
 422       */
 423      public function test_get_concurrency_limit_for_task() {
 424          global $CFG;
 425          $this->resetAfterTest(true);
 426          set_config('task_concurrency_limit_default', 10);
 427          $CFG->task_concurrency_limit = array('core\task\adhoc_test_task' => 5);
 428          $task = new adhoc_test_task();
 429          $concurrencylimit = $task->get_concurrency_limit();
 430          $this->assertEquals(5, $concurrencylimit);
 431      }
 432  
 433      /**
 434       * Test adhoc task sorting.
 435       */
 436      public function test_get_next_adhoc_task_sorting() {
 437          $this->resetAfterTest(true);
 438  
 439          // Create adhoc tasks.
 440          $task1 = new adhoc_test_task();
 441          $task1->set_next_run_time(1510000000);
 442          $task1->set_custom_data_as_string('Task 1');
 443          manager::queue_adhoc_task($task1);
 444  
 445          $task2 = new adhoc_test_task();
 446          $task2->set_next_run_time(1520000000);
 447          $task2->set_custom_data_as_string('Task 2');
 448          manager::queue_adhoc_task($task2);
 449  
 450          $task3 = new adhoc_test_task();
 451          $task3->set_next_run_time(1520000000);
 452          $task3->set_custom_data_as_string('Task 3');
 453          manager::queue_adhoc_task($task3);
 454  
 455          // Shuffle tasks.
 456          $task1->set_next_run_time(1540000000);
 457          manager::reschedule_or_queue_adhoc_task($task1);
 458  
 459          $task3->set_next_run_time(1530000000);
 460          manager::reschedule_or_queue_adhoc_task($task3);
 461  
 462          $task2->set_next_run_time(1530000000);
 463          manager::reschedule_or_queue_adhoc_task($task2);
 464  
 465          // Confirm, that tasks are sorted by nextruntime and then by id (ascending).
 466          $task = manager::get_next_adhoc_task(time());
 467          $this->assertEquals('Task 2', $task->get_custom_data_as_string());
 468          manager::adhoc_task_complete($task);
 469  
 470          $task = manager::get_next_adhoc_task(time());
 471          $this->assertEquals('Task 3', $task->get_custom_data_as_string());
 472          manager::adhoc_task_complete($task);
 473  
 474          $task = manager::get_next_adhoc_task(time());
 475          $this->assertEquals('Task 1', $task->get_custom_data_as_string());
 476          manager::adhoc_task_complete($task);
 477      }
 478  }