Proyectos de Subversion Moodle

Rev

Rev 11 | | Comparar con el anterior | Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1 efrain 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
/**
20
 * This file contains unit tests for the 'task running' data.
21
 *
22
 * @package   core
23
 * @category  test
24
 * @copyright 2019 The Open University
25
 * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
26
 */
27
final class running_test extends \advanced_testcase {
28
    public static function setUpBeforeClass(): void {
29
        require_once(__DIR__ . '/../fixtures/task_fixtures.php');
1441 ariadna 30
        parent::setUpBeforeClass();
1 efrain 31
    }
32
 
33
    /**
34
     * Test for ad-hoc tasks.
35
     */
11 efrain 36
    public function test_adhoc_task_running(): void {
1 efrain 37
        $this->resetAfterTest();
38
 
39
        // Specify lock factory. The reason is that Postgres locks don't work within a single
40
        // process (i.e. if you try to get a lock that you already locked, it will just let you)
41
        // which is usually OK but not here where we are simulating running two tasks at once in
42
        // the same process.
43
        set_config('lock_factory', '\core\lock\db_record_lock_factory');
44
 
45
        // Create and queue 2 new ad-hoc tasks.
46
        $task1 = new adhoc_test_task();
47
        $task1->set_next_run_time(time() - 20);
48
        manager::queue_adhoc_task($task1);
49
        $task2 = new adhoc_test2_task();
50
        $task2->set_next_run_time(time() - 10);
51
        manager::queue_adhoc_task($task2);
52
 
53
        // Check no tasks are marked running.
54
        $running = manager::get_running_tasks();
55
        $this->assertEmpty($running);
56
 
57
        // Mark the first task running and check results.
58
        $before = time();
59
        $next1 = manager::get_next_adhoc_task(time());
60
        manager::adhoc_task_starting($next1);
61
        $after = time();
62
        $running = manager::get_running_tasks();
63
        $this->assertCount(1, $running);
64
        foreach ($running as $item) {
65
            $this->assertEquals('adhoc', $item->type);
66
            $this->assertLessThanOrEqual($after, $item->timestarted);
67
            $this->assertGreaterThanOrEqual($before, $item->timestarted);
68
        }
69
 
70
        // Mark the second task running and check results.
71
        $next2 = manager::get_next_adhoc_task(time());
72
        manager::adhoc_task_starting($next2);
73
        $running = manager::get_running_tasks();
74
        $this->assertCount(2, $running);
75
 
76
        // Second task completes successfully.
77
        manager::adhoc_task_complete($next2);
78
        $running = manager::get_running_tasks();
79
        $this->assertCount(1, $running);
80
 
81
        // First task fails.
82
        manager::adhoc_task_failed($next1);
83
        $running = manager::get_running_tasks();
84
        $this->assertCount(0, $running);
85
    }
86
 
87
    /**
88
     * Test for scheduled tasks.
89
     */
11 efrain 90
    public function test_scheduled_task_running(): void {
1 efrain 91
        global $DB;
92
        $this->resetAfterTest();
93
 
94
        // Check no tasks are marked running.
95
        $running = manager::get_running_tasks();
96
        $this->assertEmpty($running);
97
 
98
        // Disable all the tasks, except two, and set those two due to run.
99
        $DB->set_field_select('task_scheduled', 'disabled', 1, 'classname != ? AND classname != ?',
100
                ['\core\task\session_cleanup_task', '\core\task\file_trash_cleanup_task']);
101
        $DB->set_field('task_scheduled', 'nextruntime', 1,
102
                ['classname' => '\core\task\session_cleanup_task']);
103
        $DB->set_field('task_scheduled', 'nextruntime', 1,
104
                ['classname' => '\core\task\file_trash_cleanup_task']);
105
        $DB->set_field('task_scheduled', 'lastruntime', time() - 1000,
106
                ['classname' => '\core\task\session_cleanup_task']);
107
        $DB->set_field('task_scheduled', 'lastruntime', time() - 500,
108
                ['classname' => '\core\task\file_trash_cleanup_task']);
109
 
110
        // Get the first task and start it off.
111
        $next1 = manager::get_next_scheduled_task(time());
112
        $before = time();
113
        manager::scheduled_task_starting($next1);
114
        $after = time();
115
        $running = manager::get_running_tasks();
116
        $this->assertCount(1, $running);
117
        foreach ($running as $item) {
118
            $this->assertLessThanOrEqual($after, $item->timestarted);
119
            $this->assertGreaterThanOrEqual($before, $item->timestarted);
120
            $this->assertEquals('\core\task\session_cleanup_task', $item->classname);
121
        }
122
 
123
        // Mark the second task running and check results. We have to change the times so the other
124
        // one comes up first, otherwise it repeats the same one.
125
        $DB->set_field('task_scheduled', 'lastruntime', time() - 1500,
126
                ['classname' => '\core\task\file_trash_cleanup_task']);
127
 
128
        // Make sure that there is a time gap between task to sort them as expected.
129
        sleep(1);
130
        $next2 = manager::get_next_scheduled_task(time());
131
        manager::scheduled_task_starting($next2);
132
 
133
        // Check default sorting by timestarted.
134
        $running = manager::get_running_tasks();
135
        $this->assertCount(2, $running);
136
        $item = array_shift($running);
137
        $this->assertEquals('\core\task\session_cleanup_task', $item->classname);
138
        $item = array_shift($running);
139
        $this->assertEquals('\core\task\file_trash_cleanup_task', $item->classname);
140
 
141
        // Check sorting by time ASC.
142
        $running = manager::get_running_tasks('time ASC');
143
        $this->assertCount(2, $running);
144
        $item = array_shift($running);
145
        $this->assertEquals('\core\task\file_trash_cleanup_task', $item->classname);
146
        $item = array_shift($running);
147
        $this->assertEquals('\core\task\session_cleanup_task', $item->classname);
148
 
149
        // Complete the file trash one.
150
        manager::scheduled_task_complete($next2);
151
        $running = manager::get_running_tasks();
152
        $this->assertCount(1, $running);
153
 
154
        // Other task fails.
155
        manager::scheduled_task_failed($next1);
156
        $running = manager::get_running_tasks();
157
        $this->assertCount(0, $running);
158
    }
1441 ariadna 159
 
160
    /**
161
     * Test for adhoc task cleanup.
162
     *
163
     * @covers \core\task\manager::cleanup_metadata()
164
     */
165
    public function test_adhoc_cleanup_metadata(): void {
166
        global $DB;
167
        $this->resetAfterTest(true);
168
 
169
        $clock = $this->mock_clock_with_frozen();
170
 
171
        // Specify lock factory to avoid previously mentioned issues with Postgres locks.
172
        set_config('lock_factory', '\core\lock\db_record_lock_factory');
173
 
174
        // Disable all scheduled tasks except the cleanup task.
175
        $classname = 'core\task\task_lock_cleanup_task';
176
        $DB->set_field_select('task_scheduled', 'disabled', 1, 'classname != ?', ["\\$classname"]);
177
        $DB->set_field('task_scheduled', 'nextruntime', 1, ['classname' => "\\$classname"]);
178
 
179
        // Create an adhoc task.
180
        $task = new adhoc_test_task();
181
        $task->set_next_run_time($clock->time() - MINSECS);
182
 
183
        // Queue and start the adhoc task.
184
        manager::queue_adhoc_task($task);
185
        $task = manager::get_next_adhoc_task($clock->time());
186
        manager::adhoc_task_starting($task);
187
 
188
        // Release the lock to simulate an adhoc task that has been destroyed but hasn't been cleaned up.
189
        $task->get_lock()->release();
190
        $this->assertCount(1, manager::get_running_tasks());
191
 
192
        // Run the cleanup scheduled task one hour later.
193
        $clock->bump(HOURSECS);
194
        $cleanuptask = manager::get_next_scheduled_task($clock->time());
195
        manager::scheduled_task_starting($cleanuptask);
196
        logmanager::start_logging($cleanuptask);
197
        $this->assertCount(2, manager::get_running_tasks());
198
        $cleanuptask->execute();
199
 
200
        // Confirm the task has been cleaned up.
201
        $this->assertCount(1, manager::get_running_tasks());
202
 
203
        // Check the task log hasn't been finalised for the cleanup task.
204
        $record = $DB->get_record('task_log', ['classname' => $classname]);
205
        $this->assertEmpty($record);
206
 
207
        // Now complete the task and make sure it was successful (0 = success, 1 = fail).
208
        manager::scheduled_task_complete($cleanuptask);
209
        $record = $DB->get_record('task_log', ['classname' => $classname]);
210
        $this->assertEquals(0, $record->result);
211
    }
212
 
213
    /**
214
     * Test for scheduled task cleanup.
215
     *
216
     * @covers \core\task\manager::cleanup_metadata()
217
     */
218
    public function test_scheduled_cleanup_metadata(): void {
219
        global $DB;
220
        $this->resetAfterTest(true);
221
 
222
        $clock = $this->mock_clock_with_frozen();
223
 
224
        // Specify lock factory to avoid previously mentioned issues with Postgres locks.
225
        set_config('lock_factory', '\core\lock\db_record_lock_factory');
226
 
227
        // Disable all scheduled tasks except the cleanup task.
228
        $classname = 'core\task\task_lock_cleanup_task';
229
        $DB->set_field_select('task_scheduled', 'disabled', 1, 'classname != ?', ["\\$classname"]);
230
        $DB->set_field('task_scheduled', 'nextruntime', $clock->time() + MINSECS, ['classname' => "\\$classname"]);
231
 
232
        // Create a new scheduled task.
233
        $task = new scheduled_test_task();
234
        $task->set_next_run_time($clock->time() - MINSECS);
235
 
236
        // Insert and start the test scheduled task.
237
        $DB->insert_record('task_scheduled', manager::record_from_scheduled_task($task));
238
        $task = manager::get_next_scheduled_task($clock->time());
239
        manager::scheduled_task_starting($task);
240
 
241
        // Release the lock to simulate a scheduled task that has been destroyed but hasn't been cleaned up.
242
        $task->get_lock()->release();
243
        $this->assertCount(1, manager::get_running_tasks());
244
 
245
        // Run the cleanup scheduled task one hour later.
246
        $clock->bump(HOURSECS);
247
        $cleanuptask = manager::get_next_scheduled_task($clock->time());
248
        manager::scheduled_task_starting($cleanuptask);
249
        logmanager::start_logging($cleanuptask);
250
        $this->assertCount(2, manager::get_running_tasks());
251
        $cleanuptask->execute();
252
 
253
        // Confirm the task has been cleaned up.
254
        $this->assertCount(1, manager::get_running_tasks());
255
 
256
        // Check the task log hasn't been finalised for the cleanup task.
257
        $record = $DB->get_record('task_log', ['classname' => $classname]);
258
        $this->assertEmpty($record);
259
 
260
        // Now complete the task and make sure it was successful (0 = success, 1 = fail).
261
        manager::scheduled_task_complete($cleanuptask);
262
        $record = $DB->get_record('task_log', ['classname' => $classname]);
263
        $this->assertEquals(0, $record->result);
264
    }
1 efrain 265
}