MDL-46881 core: Allow adhoc tasks to be rescheduled
[moodle.git] / lib / tests / adhoc_task_test.php
CommitLineData
309ae892
DW
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/**
0a5aa65b 18 * This file contains the unittests for adhock tasks.
309ae892
DW
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
26defined('MOODLE_INTERNAL') || die();
0a5aa65b 27require_once(__DIR__ . '/fixtures/task_fixtures.php');
309ae892
DW
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 */
0a5aa65b 38class core_adhoc_task_testcase extends advanced_testcase {
309ae892 39
dfb9daea
DNA
40 /**
41 * Test basic adhoc task execution.
42 */
43 public function test_get_next_adhoc_task_now() {
309ae892 44 $this->resetAfterTest(true);
dfb9daea 45
309ae892 46 // Create an adhoc task.
0a5aa65b 47 $task = new \core\task\adhoc_test_task();
309ae892
DW
48
49 // Queue it.
dfb9daea 50 \core\task\manager::queue_adhoc_task($task);
309ae892
DW
51
52 $now = time();
53 // Get it from the scheduler.
54 $task = \core\task\manager::get_next_adhoc_task($now);
dfb9daea 55 $this->assertInstanceOf('\\core\\task\\adhoc_test_task', $task);
309ae892 56 $task->execute();
dfb9daea
DNA
57 \core\task\manager::adhoc_task_complete($task);
58 }
309ae892 59
dfb9daea
DNA
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.
309ae892 73 $task = \core\task\manager::get_next_adhoc_task($now);
dfb9daea
DNA
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));
309ae892
DW
79
80 // Should get the adhoc task (retry after delay).
81 $task = \core\task\manager::get_next_adhoc_task($now + 120);
dfb9daea 82 $this->assertInstanceOf('\\core\\task\\adhoc_test_task', $task);
309ae892
DW
83 $task->execute();
84
85 \core\task\manager::adhoc_task_complete($task);
86
87 // Should not get any task.
dfb9daea
DNA
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);
309ae892 111 }
0f268f5d
RW
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 }
96e1633f 152
b51b6969
AN
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
96e1633f
MG
261 /**
262 * Test queue_adhoc_task "if not scheduled".
263 */
264 public function test_queue_adhoc_task_if_not_scheduled() {
265 $this->resetAfterTest(true);
7e4c4b6f 266 $user = \core_user::get_user_by_username('admin');
96e1633f
MG
267
268 // Schedule adhoc task.
7e4c4b6f
AN
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));
96e1633f
MG
272 $this->assertEquals(1, count(\core\task\manager::get_adhoc_tasks('core\task\adhoc_test_task')));
273
7e4c4b6f
AN
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));
96e1633f
MG
279 $this->assertEquals(2, count(\core\task\manager::get_adhoc_tasks('core\task\adhoc_test_task')));
280
7e4c4b6f
AN
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
96e1633f 287 // Schedule same adhoc task with same custom data.
7e4c4b6f
AN
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')));
96e1633f
MG
299
300 // Schedule same adhoc task without custom data.
7e4c4b6f
AN
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')));
96e1633f
MG
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));
7e4c4b6f
AN
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);
96e1633f 362
7e4c4b6f 363 $this->assertEquals($user->id, $task->get_userid());
96e1633f 364 }
309ae892 365}