Search moodle.org's
Developer Documentation

See Release Notes
Long Term Support Release

  • Bug fixes for general core bugs in 3.9.x will end* 10 May 2021 (12 months).
  • Bug fixes for security issues in 3.9.x will end* 8 May 2023 (36 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 empty set of adhoc tasks
 115       */
 116      public function test_get_adhoc_tasks_empty_set() {
 117          $this->resetAfterTest(true);
 118  
 119          $this->assertEquals([], \core\task\manager::get_adhoc_tasks('\\core\\task\\adhoc_test_task'));
 120      }
 121  
 122      /**
 123       * Test correct set of adhoc tasks is returned for class.
 124       */
 125      public function test_get_adhoc_tasks_result_set() {
 126          $this->resetAfterTest(true);
 127  
 128          for ($i = 0; $i < 3; $i++) {
 129              $task = new \core\task\adhoc_test_task();
 130              \core\task\manager::queue_adhoc_task($task);
 131          }
 132  
 133          for ($i = 0; $i < 3; $i++) {
 134              $task = new \core\task\adhoc_test2_task();
 135              \core\task\manager::queue_adhoc_task($task);
 136          }
 137  
 138          $adhoctests = \core\task\manager::get_adhoc_tasks('\\core\\task\\adhoc_test_task');
 139          $adhoctest2s = \core\task\manager::get_adhoc_tasks('\\core\\task\\adhoc_test2_task');
 140  
 141          $this->assertCount(3, $adhoctests);
 142          $this->assertCount(3, $adhoctest2s);
 143  
 144          foreach ($adhoctests as $task) {
 145              $this->assertInstanceOf('\\core\\task\\adhoc_test_task', $task);
 146          }
 147  
 148          foreach ($adhoctest2s as $task) {
 149              $this->assertInstanceOf('\\core\\task\\adhoc_test2_task', $task);
 150          }
 151      }
 152  
 153      /**
 154       * Ensure that the reschedule_or_queue_adhoc_task function will schedule a new task if no tasks exist.
 155       */
 156      public function test_reschedule_or_queue_adhoc_task_no_existing() {
 157          $this->resetAfterTest(true);
 158  
 159          // Schedule adhoc task.
 160          $task = new \core\task\adhoc_test_task();
 161          $task->set_custom_data(['courseid' => 10]);
 162          \core\task\manager::reschedule_or_queue_adhoc_task($task);
 163          $this->assertEquals(1, count(\core\task\manager::get_adhoc_tasks('core\task\adhoc_test_task')));
 164      }
 165  
 166      /**
 167       * Ensure that the reschedule_or_queue_adhoc_task function will schedule a new task if a task for the same user does
 168       * not exist.
 169       */
 170      public function test_reschedule_or_queue_adhoc_task_different_user() {
 171          $this->resetAfterTest(true);
 172          $user = \core_user::get_user_by_username('admin');
 173  
 174          // Schedule adhoc task.
 175          $task = new \core\task\adhoc_test_task();
 176          $task->set_custom_data(['courseid' => 10]);
 177          \core\task\manager::reschedule_or_queue_adhoc_task($task);
 178  
 179          // Schedule adhoc task for a different user.
 180          $task = new \core\task\adhoc_test_task();
 181          $task->set_custom_data(['courseid' => 10]);
 182          $task->set_userid($user->id);
 183          \core\task\manager::reschedule_or_queue_adhoc_task($task);
 184  
 185          $this->assertEquals(2, count(\core\task\manager::get_adhoc_tasks('core\task\adhoc_test_task')));
 186      }
 187  
 188      /**
 189       * Ensure that the reschedule_or_queue_adhoc_task function will schedule a new task if a task with different custom
 190       * data exists.
 191       */
 192      public function test_reschedule_or_queue_adhoc_task_different_data() {
 193          $this->resetAfterTest(true);
 194  
 195          // Schedule adhoc task.
 196          $task = new \core\task\adhoc_test_task();
 197          $task->set_custom_data(['courseid' => 10]);
 198          \core\task\manager::reschedule_or_queue_adhoc_task($task);
 199  
 200          // Schedule adhoc task for a different user.
 201          $task = new \core\task\adhoc_test_task();
 202          $task->set_custom_data(['courseid' => 11]);
 203          \core\task\manager::reschedule_or_queue_adhoc_task($task);
 204  
 205          $this->assertEquals(2, count(\core\task\manager::get_adhoc_tasks('core\task\adhoc_test_task')));
 206      }
 207  
 208      /**
 209       * Ensure that the reschedule_or_queue_adhoc_task function will not make any change for matching data if no time was
 210       * specified.
 211       */
 212      public function test_reschedule_or_queue_adhoc_task_match_no_change() {
 213          $this->resetAfterTest(true);
 214  
 215          // Schedule adhoc task.
 216          $task = new \core\task\adhoc_test_task();
 217          $task->set_custom_data(['courseid' => 10]);
 218          $task->set_next_run_time(time() + DAYSECS);
 219          \core\task\manager::reschedule_or_queue_adhoc_task($task);
 220  
 221          $before = \core\task\manager::get_adhoc_tasks('core\task\adhoc_test_task');
 222  
 223          // Schedule the task again but do not specify a time.
 224          $task = new \core\task\adhoc_test_task();
 225          $task->set_custom_data(['courseid' => 10]);
 226          \core\task\manager::reschedule_or_queue_adhoc_task($task);
 227  
 228          $this->assertEquals(1, count(\core\task\manager::get_adhoc_tasks('core\task\adhoc_test_task')));
 229          $this->assertEquals($before, \core\task\manager::get_adhoc_tasks('core\task\adhoc_test_task'));
 230      }
 231  
 232      /**
 233       * Ensure that the reschedule_or_queue_adhoc_task function will update the run time if there are planned changes.
 234       */
 235      public function test_reschedule_or_queue_adhoc_task_match_update_runtime() {
 236          $this->resetAfterTest(true);
 237          $initialruntime = time() + DAYSECS;
 238          $newruntime = time() + WEEKSECS;
 239  
 240          // Schedule adhoc task.
 241          $task = new \core\task\adhoc_test_task();
 242          $task->set_custom_data(['courseid' => 10]);
 243          $task->set_next_run_time($initialruntime);
 244          \core\task\manager::reschedule_or_queue_adhoc_task($task);
 245  
 246          $before = \core\task\manager::get_adhoc_tasks('core\task\adhoc_test_task');
 247  
 248          // Schedule the task again.
 249          $task = new \core\task\adhoc_test_task();
 250          $task->set_custom_data(['courseid' => 10]);
 251          $task->set_next_run_time($newruntime);
 252          \core\task\manager::reschedule_or_queue_adhoc_task($task);
 253  
 254          $tasks = \core\task\manager::get_adhoc_tasks('core\task\adhoc_test_task');
 255          $this->assertEquals(1, count($tasks));
 256          $this->assertNotEquals($before, $tasks);
 257          $firsttask = reset($tasks);
 258          $this->assertEquals($newruntime, $firsttask->get_next_run_time());
 259      }
 260  
 261      /**
 262       * Test queue_adhoc_task "if not scheduled".
 263       */
 264      public function test_queue_adhoc_task_if_not_scheduled() {
 265          $this->resetAfterTest(true);
 266          $user = \core_user::get_user_by_username('admin');
 267  
 268          // Schedule adhoc task.
 269          $task = new \core\task\adhoc_test_task();
 270          $task->set_custom_data(array('courseid' => 10));
 271          $this->assertNotEmpty(\core\task\manager::queue_adhoc_task($task, true));
 272          $this->assertEquals(1, count(\core\task\manager::get_adhoc_tasks('core\task\adhoc_test_task')));
 273  
 274          // Schedule adhoc task with a user.
 275          $task = new \core\task\adhoc_test_task();
 276          $task->set_custom_data(array('courseid' => 10));
 277          $task->set_userid($user->id);
 278          $this->assertNotEmpty(\core\task\manager::queue_adhoc_task($task, true));
 279          $this->assertEquals(2, count(\core\task\manager::get_adhoc_tasks('core\task\adhoc_test_task')));
 280  
 281          // Schedule same adhoc task with different custom data.
 282          $task = new \core\task\adhoc_test_task();
 283          $task->set_custom_data(array('courseid' => 1));
 284          $this->assertNotEmpty(\core\task\manager::queue_adhoc_task($task, true));
 285          $this->assertEquals(3, count(\core\task\manager::get_adhoc_tasks('core\task\adhoc_test_task')));
 286  
 287          // Schedule same adhoc task with same custom data.
 288          $task = new \core\task\adhoc_test_task();
 289          $task->set_custom_data(array('courseid' => 1));
 290          $this->assertEmpty(\core\task\manager::queue_adhoc_task($task, true));
 291          $this->assertEquals(3, count(\core\task\manager::get_adhoc_tasks('core\task\adhoc_test_task')));
 292  
 293          // Schedule same adhoc task with same custom data and a user.
 294          $task = new \core\task\adhoc_test_task();
 295          $task->set_custom_data(array('courseid' => 1));
 296          $task->set_userid($user->id);
 297          $this->assertNotEmpty(\core\task\manager::queue_adhoc_task($task, true));
 298          $this->assertEquals(4, count(\core\task\manager::get_adhoc_tasks('core\task\adhoc_test_task')));
 299  
 300          // Schedule same adhoc task without custom data.
 301          // Note: This task was created earlier.
 302          $task = new \core\task\adhoc_test_task();
 303          $this->assertNotEmpty(\core\task\manager::queue_adhoc_task($task, true));
 304          $this->assertEquals(5, count(\core\task\manager::get_adhoc_tasks('core\task\adhoc_test_task')));
 305  
 306          // Schedule same adhoc task without custom data (again).
 307          $task5 = new \core\task\adhoc_test_task();
 308          $this->assertEmpty(\core\task\manager::queue_adhoc_task($task5, true));
 309          $this->assertEquals(5, count(\core\task\manager::get_adhoc_tasks('core\task\adhoc_test_task')));
 310  
 311          // Schedule same adhoc task without custom data but with a userid.
 312          $task6 = new \core\task\adhoc_test_task();
 313          $user = \core_user::get_user_by_username('admin');
 314          $task6->set_userid($user->id);
 315          $this->assertNotEmpty(\core\task\manager::queue_adhoc_task($task6, true));
 316          $this->assertEquals(6, count(\core\task\manager::get_adhoc_tasks('core\task\adhoc_test_task')));
 317  
 318          // Schedule same adhoc task again without custom data but with a userid.
 319          $task6 = new \core\task\adhoc_test_task();
 320          $user = \core_user::get_user_by_username('admin');
 321          $task6->set_userid($user->id);
 322          $this->assertEmpty(\core\task\manager::queue_adhoc_task($task6, true));
 323          $this->assertEquals(6, count(\core\task\manager::get_adhoc_tasks('core\task\adhoc_test_task')));
 324      }
 325  
 326      /**
 327       * Test that when no userid is specified, it returns empty from the DB
 328       * too.
 329       */
 330      public function test_adhoc_task_user_empty() {
 331          $this->resetAfterTest(true);
 332  
 333          // Create an adhoc task in future.
 334          $task = new \core\task\adhoc_test_task();
 335          \core\task\manager::queue_adhoc_task($task);
 336  
 337          // Get it back from the scheduler.
 338          $now = time();
 339          $task = \core\task\manager::get_next_adhoc_task($now);
 340          \core\task\manager::adhoc_task_complete($task);
 341  
 342          $this->assertEmpty($task->get_userid());
 343      }
 344  
 345      /**
 346       * Test that when a userid is specified, that userid is subsequently
 347       * returned.
 348       */
 349      public function test_adhoc_task_user_set() {
 350          $this->resetAfterTest(true);
 351  
 352          // Create an adhoc task in future.
 353          $task = new \core\task\adhoc_test_task();
 354          $user = \core_user::get_user_by_username('admin');
 355          $task->set_userid($user->id);
 356          \core\task\manager::queue_adhoc_task($task);
 357  
 358          // Get it back from the scheduler.
 359          $now = time();
 360          $task = \core\task\manager::get_next_adhoc_task($now);
 361          \core\task\manager::adhoc_task_complete($task);
 362  
 363          $this->assertEquals($user->id, $task->get_userid());
 364      }
 365  
 366      /**
 367       * Test get_concurrency_limit() method to return 0 by default.
 368       */
 369      public function test_get_concurrency_limit() {
 370          $this->resetAfterTest(true);
 371          $task = new \core\task\adhoc_test_task();
 372          $concurrencylimit = $task->get_concurrency_limit();
 373          $this->assertEquals(0, $concurrencylimit);
 374      }
 375  
 376      /**
 377       * Test get_concurrency_limit() method to return a default value set in config.
 378       */
 379      public function test_get_concurrency_limit_default() {
 380          $this->resetAfterTest(true);
 381          set_config('task_concurrency_limit_default', 10);
 382          $task = new \core\task\adhoc_test_task();
 383          $concurrencylimit = $task->get_concurrency_limit();
 384          $this->assertEquals(10, $concurrencylimit);
 385      }
 386  
 387      /**
 388       * Test get_concurrency_limit() method to return a value for specific task class.
 389       */
 390      public function test_get_concurrency_limit_for_task() {
 391          global $CFG;
 392          $this->resetAfterTest(true);
 393          set_config('task_concurrency_limit_default', 10);
 394          $CFG->task_concurrency_limit = array('core\task\adhoc_test_task' => 5);
 395          $task = new \core\task\adhoc_test_task();
 396          $concurrencylimit = $task->get_concurrency_limit();
 397          $this->assertEquals(5, $concurrencylimit);
 398      }
 399  
 400      /**
 401       * Test adhoc task sorting.
 402       */
 403      public function test_get_next_adhoc_task_sorting() {
 404          $this->resetAfterTest(true);
 405  
 406          // Create adhoc tasks.
 407          $task1 = new \core\task\adhoc_test_task();
 408          $task1->set_next_run_time(1510000000);
 409          $task1->set_custom_data_as_string('Task 1');
 410          \core\task\manager::queue_adhoc_task($task1);
 411  
 412          $task2 = new \core\task\adhoc_test_task();
 413          $task2->set_next_run_time(1520000000);
 414          $task2->set_custom_data_as_string('Task 2');
 415          \core\task\manager::queue_adhoc_task($task2);
 416  
 417          $task3 = new \core\task\adhoc_test_task();
 418          $task3->set_next_run_time(1520000000);
 419          $task3->set_custom_data_as_string('Task 3');
 420          \core\task\manager::queue_adhoc_task($task3);
 421  
 422          // Shuffle tasks.
 423          $task1->set_next_run_time(1540000000);
 424          \core\task\manager::reschedule_or_queue_adhoc_task($task1);
 425  
 426          $task3->set_next_run_time(1530000000);
 427          \core\task\manager::reschedule_or_queue_adhoc_task($task3);
 428  
 429          $task2->set_next_run_time(1530000000);
 430          \core\task\manager::reschedule_or_queue_adhoc_task($task2);
 431  
 432          // Confirm, that tasks are sorted by nextruntime and then by id (ascending).
 433          $task = \core\task\manager::get_next_adhoc_task(time());
 434          $this->assertEquals('Task 2', $task->get_custom_data_as_string());
 435          \core\task\manager::adhoc_task_complete($task);
 436  
 437          $task = \core\task\manager::get_next_adhoc_task(time());
 438          $this->assertEquals('Task 3', $task->get_custom_data_as_string());
 439          \core\task\manager::adhoc_task_complete($task);
 440  
 441          $task = \core\task\manager::get_next_adhoc_task(time());
 442          $this->assertEquals('Task 1', $task->get_custom_data_as_string());
 443          \core\task\manager::adhoc_task_complete($task);
 444      }
 445  }