diff --git a/lib/tests/fixtures/task_fixtures.php b/lib/tests/fixtures/task_fixtures.php index 9ece85de6811b..eb910106e9288 100644 --- a/lib/tests/fixtures/task_fixtures.php +++ b/lib/tests/fixtures/task_fixtures.php @@ -26,16 +26,78 @@ namespace core\task; defined('MOODLE_INTERNAL') || die(); +/** + * Test class. + * + * @copyright 2022 Catalyst IT Australia Pty Ltd + * @author Cameron Ball + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ class adhoc_test_task extends \core\task\adhoc_task { - public function execute() { + + /** + * Constructor. + * + * @param int|null $nextruntime Next run time + * @param int|null $timestarted Time started + */ + public function __construct(?int $nextruntime = null, ?int $timestarted = null) { + if ($nextruntime) { + $this->set_next_run_time($nextruntime); + } + + if ($timestarted) { + $this->set_timestarted($timestarted); + } } -} -class adhoc_test2_task extends \core\task\adhoc_task { + /** + * Execute. + */ public function execute() { } } +/** + * Test class. + * + * @copyright 2022 Catalyst IT Australia Pty Ltd + * @author Cameron Ball + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class adhoc_test2_task extends adhoc_test_task { +} + +/** + * Test class. + * + * @copyright 2022 Catalyst IT Australia Pty Ltd + * @author Cameron Ball + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class adhoc_test3_task extends adhoc_test_task { +} + +/** + * Test class. + * + * @copyright 2022 Catalyst IT Australia Pty Ltd + * @author Cameron Ball + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class adhoc_test4_task extends adhoc_test_task { +} + +/** + * Test class. + * + * @copyright 2022 Catalyst IT Australia Pty Ltd + * @author Cameron Ball + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class adhoc_test5_task extends adhoc_test_task { +} + class scheduled_test_task extends \core\task\scheduled_task { public function get_name() { return "Test task"; diff --git a/lib/tests/task_manager_test.php b/lib/tests/task_manager_test.php new file mode 100644 index 0000000000000..59eb8f38393eb --- /dev/null +++ b/lib/tests/task_manager_test.php @@ -0,0 +1,248 @@ +. + +/** + * This file contains the unit tests for the task manager. + * + * @package core + * @copyright 2019 Brendan Heywood + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +namespace core\task; + +defined('MOODLE_INTERNAL') || die(); +require_once(__DIR__ . '/fixtures/task_fixtures.php'); + +/** + * This file contains the unit tests for the task manager. + * + * @copyright 2019 Brendan Heywood + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class task_manager_test extends \advanced_testcase { + + /** + * Data provider for test_get_candidate_adhoc_tasks. + * + * @return array + */ + public function test_get_candidate_adhoc_tasks_provider(): array { + return [ + [ + 'concurrencylimit' => 5, + 'limit' => 100, + 'pertasklimits' => [], + 'tasks' => [ + new adhoc_test_task(time() - 20, null), + new adhoc_test_task(time() - 20, null), + new adhoc_test_task(time() - 20, null), + new adhoc_test_task(time() - 20, null), + new adhoc_test_task(time() - 20, null) + ], + 'expected' => [ + adhoc_test_task::class, + adhoc_test_task::class, + adhoc_test_task::class, + adhoc_test_task::class, + adhoc_test_task::class + ] + ], + [ + 'concurrencylimit' => 5, + 'limit' => 100, + 'pertasklimits' => [], + 'tasks' => [ + new adhoc_test_task(time() - 20, time()), + new adhoc_test_task(time() - 20, null), + new adhoc_test_task(time() - 20, null), + new adhoc_test_task(time() - 20, null), + new adhoc_test_task(time() - 20, null) + ], + 'expected' => [ + adhoc_test_task::class, + adhoc_test_task::class, + adhoc_test_task::class, + adhoc_test_task::class + ] + ], + [ + 'concurrencylimit' => 1, + 'limit' => 100, + 'pertasklimits' => [], + 'tasks' => [ + new adhoc_test_task(time() - 20, time()), + new adhoc_test_task(time() - 20, null), + new adhoc_test_task(time() - 20, null), + new adhoc_test_task(time() - 20, null), + new adhoc_test_task(time() - 20, null) + ], + 'expected' => [] + ], + [ + 'concurrencylimit' => 2, + 'limit' => 100, + 'pertasklimits' => [], + 'tasks' => [ + new adhoc_test_task(time() - 20, time()), + new adhoc_test_task(time() - 20, time()), + new adhoc_test_task(time() - 20, null), + new adhoc_test_task(time() - 20, null), + new adhoc_test_task(time() - 20, null) + ], + 'expected' => [] + ], + [ + 'concurrencylimit' => 2, + 'limit' => 100, + 'pertasklimits' => [], + 'tasks' => [ + new adhoc_test_task(time() - 20, time()), + new adhoc_test_task(time() - 20, time()), + new adhoc_test2_task(time() - 20, time()), + new adhoc_test2_task(time() - 20, time()), + new adhoc_test3_task(time() - 20, null) + ], + 'expected' => [adhoc_test3_task::class] + ], + [ + 'concurrencylimit' => 2, + 'limit' => 2, + 'pertasklimits' => [], + 'tasks' => [ + new adhoc_test_task(time() - 20, null), + new adhoc_test_task(time() - 20, null), + new adhoc_test_task(time() - 20, null), + new adhoc_test2_task(time() - 20, null), + ], + 'expected' => [ + adhoc_test_task::class, + adhoc_test_task::class + ] + ], + [ + 'concurrencylimit' => 2, + 'limit' => 2, + 'pertasklimits' => [], + 'tasks' => [ + new adhoc_test_task(time() - 20, time()), + new adhoc_test_task(time() - 20, time()), + new adhoc_test_task(time() - 20, null), + new adhoc_test2_task(time() - 20, null), + ], + 'expected' => [ + adhoc_test2_task::class + ] + ], + [ + 'concurrencylimit' => 3, + 'limit' => 100, + 'pertasklimits' => [], + 'tasks' => [ + new adhoc_test_task(time() - 20, time()), + new adhoc_test_task(time() - 20, time()), + new adhoc_test_task(time() - 20, null), + new adhoc_test2_task(time() - 20, time()), + new adhoc_test2_task(time() - 20, time()), + new adhoc_test2_task(time() - 20, null), + new adhoc_test3_task(time() - 20, time()), + new adhoc_test3_task(time() - 20, time()), + new adhoc_test3_task(time() - 20, null), + new adhoc_test4_task(time() - 20, time()), + new adhoc_test4_task(time() - 20, time()), + new adhoc_test4_task(time() - 20, null), + new adhoc_test5_task(time() - 20, time()), + new adhoc_test5_task(time() - 20, time()), + new adhoc_test5_task(time() - 20, null), + ], + 'expected' => [ + adhoc_test_task::class, + adhoc_test2_task::class, + adhoc_test3_task::class, + adhoc_test4_task::class, + adhoc_test5_task::class + ] + ], + [ + 'concurrencylimit' => 3, + 'limit' => 100, + 'pertasklimits' => [ + 'adhoc_test_task' => 2, + 'adhoc_test2_task' => 2, + 'adhoc_test3_task' => 2, + 'adhoc_test4_task' => 2, + 'adhoc_test5_task' => 2 + ], + 'tasks' => [ + new adhoc_test_task(time() - 20, time()), + new adhoc_test_task(time() - 20, time()), + new adhoc_test_task(time() - 20, null), + new adhoc_test2_task(time() - 20, time()), + new adhoc_test2_task(time() - 20, time()), + new adhoc_test2_task(time() - 20, null), + new adhoc_test3_task(time() - 20, time()), + new adhoc_test3_task(time() - 20, time()), + new adhoc_test3_task(time() - 20, null), + new adhoc_test4_task(time() - 20, time()), + new adhoc_test4_task(time() - 20, time()), + new adhoc_test4_task(time() - 20, null), + new adhoc_test5_task(time() - 20, time()), + new adhoc_test5_task(time() - 20, time()), + new adhoc_test5_task(time() - 20, null), + ], + 'expected' => [] + ] + ]; + } + + /** + * Test that the candidate adhoc tasks are returned in the right order. + * + * @dataProvider test_get_candidate_adhoc_tasks_provider + * + * @param int $concurrencylimit The max number of runners each task can consume + * @param int $limit SQL limit + * @param array $pertasklimits Per-task limits + * @param array $tasks Array of tasks to put in DB and retrieve + * @param array $expected Array of expected classnames + * @return void + * @covers \manager::get_candidate_adhoc_tasks + */ + public function test_get_candidate_adhoc_tasks( + int $concurrencylimit, + int $limit, + array $pertasklimits, + array $tasks, + array $expected + ): void { + $this->resetAfterTest(); + + foreach ($tasks as $task) { + manager::queue_adhoc_task($task); + } + + $candidates = manager::get_candidate_adhoc_tasks(time(), $limit, $concurrencylimit, $pertasklimits); + $this->assertEquals( + array_map( + function(string $classname): string { + return '\\' . $classname; + }, + $expected + ), + array_column($candidates, 'classname') + ); + } +}