Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 3.10.x will end 8 November 2021 (12 months).
  • Bug fixes for security issues in 3.10.x will end 9 May 2022 (18 months).
  • PHP version: minimum PHP 7.2.0 Note: minimum PHP version has increased since Moodle 3.8. PHP 7.3.x and 7.4.x are supported too.

Differences Between: [Versions 39 and 310]

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