Proyectos de Subversion Moodle

Rev

| 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 mod_bigbluebuttonbn\task;
18
 
19
use advanced_testcase;
20
use core\task\manager;
21
use mod_bigbluebuttonbn\instance;
22
use mod_bigbluebuttonbn\logger;
23
use mod_bigbluebuttonbn\recording;
24
use mod_bigbluebuttonbn\test\testcase_helper_trait;
25
 
26
/**
27
 * Class containing the scheduled task for lti module.
28
 *
29
 * @package   mod_bigbluebuttonbn
30
 * @copyright 2019 onwards, Blindside Networks Inc
31
 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
32
 * @covers \mod_bigbluebuttonbn\task\upgrade_recordings_task
33
 */
34
class upgrade_recordings_task_test extends advanced_testcase {
35
 
36
    use testcase_helper_trait;
37
 
38
    /**
39
     * @var object $instance
40
     */
41
    protected $instance = null;
42
 
43
    /**
44
     * @var array $groups all groups
45
     */
46
    protected $groups = [];
47
 
48
    /**
49
     * Setup for test
50
     */
51
    public function setUp(): void {
52
        parent::setUp();
53
        $this->initialise_mock_server();
54
        $this->resetAfterTest();
55
    }
56
 
57
    /**
58
     * Upgrade task test
59
     */
60
    public function test_upgrade_recordings_basic(): void {
61
        global $DB;
62
        $this->setup_basic_data();
63
        upgrade_recordings_task::schedule_upgrade_per_meeting(false);;
64
        // The first run will lead to all of them being processed, and none left over.
65
        // A new job is always queued on a successful run.
66
        $this->runAdhocTasks(upgrade_recordings_task::class);
67
        $this->assertEquals(0, $DB->count_records('bigbluebuttonbn_logs', ['log' => logger::EVENT_CREATE]));
68
        $this->assertEquals(75, recording::count_records(['imported' => '0']));
69
        // Old logs are kept but renamed.
70
        $this->assertEquals(75, $DB->count_records('bigbluebuttonbn_logs', ['log' => logger::EVENT_CREATE_MIGRATED]));
71
        $this->assertEquals(15, recording::count_records(['groupid' => $this->groups[0]->id, 'imported' => '0',
72
            'status' => recording::RECORDING_STATUS_PROCESSED]));
73
        $this->assertEquals(15, recording::count_records(['groupid' => $this->groups[1]->id, 'imported' => '0',
74
            'status' => recording::RECORDING_STATUS_PROCESSED]));
75
        $this->assertEquals(45,
76
            recording::count_records(['groupid' => 0, 'imported' => '0', 'status' => recording::RECORDING_STATUS_PROCESSED]));
77
 
78
        // The second run will lead to no change in the number of logs, but no further jobs will be queued.
79
        upgrade_recordings_task::schedule_upgrade_per_meeting();
80
        $this->runAdhocTasks(upgrade_recordings_task::class);
81
        $this->assertEquals(75, recording::count_records());
82
        // The first run will lead to all of them being processed, and none left over.
83
        // A new job is always queued on a successful run.
84
        $this->assertEmpty($DB->get_records_select(
85
            'bigbluebuttonbn_logs',
86
            'log = :logmatch AND ' . $DB->sql_like('meta', ':match'),
87
            [
88
                'logmatch' => 'Create',
89
                'match' => '%true%'
90
            ]
91
        ));
92
        $this->runAdhocTasks(upgrade_recordings_task::class);
93
        $this->assertEmpty($DB->get_records_select(
94
            'bigbluebuttonbn_logs',
95
            'log = :logmatch AND ' . $DB->sql_like('meta', ':match'),
96
            [
97
                'logmatch' => 'Create',
98
                'match' => '%true%'
99
            ]
100
        ));
101
        $this->assertEquals(0, $DB->count_records('bigbluebuttonbn_logs', ['log' => 'Create']));
102
        // Ensure that logs match.
103
        $matchesarray = [
104
            [
105
                'Executing .*',
106
                'Fetching logs for conversion',
107
                "Creating new recording records",
108
                'Migrated 30 recordings',
109
            ],
110
            [
111
                'Executing .*',
112
                'Fetching logs for conversion',
113
                "Creating new recording records",
114
                'Migrated 15 recordings',
115
            ],
116
            [
117
                'Executing .*',
118
                'Fetching logs for conversion',
119
                "Creating new recording records",
120
                "Unable to find an activity for .*. This recording is headless",
121
                'Migrated 15 recordings'
122
            ]
123
        ];
124
        foreach ($matchesarray as $matches) {
125
            $this->expectOutputRegex('/' . implode('.*', $matches) . '/s');
126
        }
127
        $this->resetDebugging(); // We might have debugging message that are sent by get_from_meetingid and can ignore them.
128
    }
129
 
130
    /**
131
     * Upgrade task test
132
     */
133
    public function test_upgrade_recordings_imported_basic(): void {
134
        global $DB;
135
        $this->setup_basic_data(true);
136
        upgrade_recordings_task::schedule_upgrade_per_meeting(true);;
137
        // The first run will lead to all of them being processed, and none left over.
138
        // A new job is always queued on a successful run.
139
        $this->runAdhocTasks(upgrade_recordings_task::class);
140
 
141
        $this->assertEquals(0, $DB->count_records('bigbluebuttonbn_logs', ['log' => logger::EVENT_IMPORT]));
142
        $this->assertEquals(75, $DB->count_records('bigbluebuttonbn_logs', ['log' => logger::EVENT_IMPORT_MIGRATED]));
143
        $this->assertEquals(75, recording::count_records(['imported' => '1']));
144
 
145
        $this->assertEquals(15, recording::count_records(['groupid' => $this->groups[0]->id, 'imported' => '1',
146
            'status' => recording::RECORDING_STATUS_PROCESSED]));
147
        $this->assertEquals(15, recording::count_records(['groupid' => $this->groups[1]->id, 'imported' => '1',
148
            'status' => recording::RECORDING_STATUS_PROCESSED]));
149
        $this->assertEquals(45,
150
            recording::count_records(['groupid' => 0, 'imported' => '1', 'status' => recording::RECORDING_STATUS_PROCESSED]));
151
 
152
        // The second run will lead to no change in the number of logs, but no further jobs will be queued.
153
        upgrade_recordings_task::schedule_upgrade_per_meeting();
154
        $this->runAdhocTasks(upgrade_recordings_task::class);
155
        $this->assertEquals(75, recording::count_records(['imported' => '1']));
156
        // The first run will lead to all of them being processed, and none left over.
157
        // A new job is always queued on a successful run.
158
        $this->assertEmpty($DB->get_records_select(
159
            'bigbluebuttonbn_logs',
160
            'log = :logmatch',
161
            [
162
                'logmatch' => 'Import'
163
            ]
164
        ));
165
        // Ensure that logs match.
166
        $matchesarray = [
167
            [
168
                'Executing .*',
169
                'Fetching logs for conversion',
170
                "Creating new recording records",
171
                'Migrated 30 recordings',
172
            ],
173
            [
174
                'Executing .*',
175
                'Fetching logs for conversion',
176
                "Creating new recording records",
177
                'Migrated 15 recordings',
178
            ],
179
            [
180
                'Executing .*',
181
                'Fetching logs for conversion',
182
                "Creating new recording records",
183
                "Unable to find an activity for .*. This recording is headless",
184
                'Migrated 15 recordings'
185
            ]
186
        ];
187
        foreach ($matchesarray as $matches) {
188
            $this->expectOutputRegex('/' . implode('.*', $matches) . '/s');
189
        }
190
        $this->resetDebugging(); // We might have debugging message that are sent by get_from_meetingid and can ignore them.
191
    }
192
 
193
    /**
194
     * Upgrade recordings when we have missing recordings on the server
195
     * Basically, the recordings are imported and then we cannot the other because logs have been marked as migrated.
196
     */
197
    public function test_upgrade_recordings_with_missing_recording_on_bbb_server(): void {
198
        global $DB;
199
        $plugingenerator = $this->getDataGenerator()->get_plugin_generator('mod_bigbluebuttonbn');
200
        [$teacher, $groups, $instance, $groupedinstance, $deletedinstance] = $this->setup_basic_course_and_meeting();
201
 
202
        $this->create_log_entries($instance, $teacher->id, 5);
203
        $this->create_log_entries($instance, $teacher->id, 5, false, false);
204
        $this->assertEquals(10, $DB->count_records('bigbluebuttonbn_logs', ['log' => 'Create']));
205
 
206
        // Schedule the run.
207
        upgrade_recordings_task::schedule_upgrade_per_meeting();
208
        $this->runAdhocTasks(upgrade_recordings_task::class);
209
        // At this point only 5 are created, the rest is still in the queue.
210
        $this->assertEquals(0, $DB->count_records('bigbluebuttonbn_logs', ['log' => 'Create']));
211
        $this->assertEquals(5, recording::count_records());
212
        // Now create 5 recordings on the server.
213
        // Schedule the run.
214
        upgrade_recordings_task::schedule_upgrade_per_meeting();
215
        for ($index = 0; $index < 5; $index++) {
216
            $plugingenerator->create_recording([
217
                'bigbluebuttonbnid' => $instance->get_instance_id(),
218
                'groupid' => $instance->get_group_id(),
219
                'starttime' => time(),
220
                'endtime' => time() + HOURSECS,
221
            ], true); // Create another recording on the server.
222
        }
223
        $this->assertEquals(0, $DB->count_records('task_adhoc', ['classname' => '\\' . upgrade_recordings_task::class]));
224
        $this->runAdhocTasks(upgrade_recordings_task::class);
225
        // Ensure that logs match.
226
 
227
        // Ensure that logs match.
228
        $matchesarray = [
229
            [
230
                'Executing .*',
231
                'Fetching logs for conversion',
232
                "Creating new recording records",
233
                'Migrated 5 recordings',
234
            ],
235
        ];
236
        foreach ($matchesarray as $matches) {
237
            $this->expectOutputRegex('/' . implode('.*', $matches) . '/s');
238
        }
239
    }
240
 
241
    /**
242
     * Upgrade task test with more recordings on the server than in the log : we add all recording and should have
243
     * no more logs.
244
     */
245
    public function test_upgrade_recordings_with_more_recordings_on_bbb_server(): void {
246
        global $DB;
247
        $generator = $this->getDataGenerator();
248
        // Create a course with student and teacher, and two groups.
249
        $this->course = $generator->create_course();
250
        $user = $this->getDataGenerator()->create_and_enrol($this->course);
251
        // Create an ungrouped activity.
252
        $activity = $generator->create_module('bigbluebuttonbn', [
253
            'course' => $this->course->id,
254
        ]);
255
        $this->instance = instance::get_from_instanceid($activity->id);
256
        // We create 5 recordings in the log but no recording instance on the server.
257
        $plugingenerator = $this->getDataGenerator()->get_plugin_generator('mod_bigbluebuttonbn');
258
        $plugingenerator->create_meeting([
259
            'instanceid' => $this->instance->get_instance_id(),
260
            'groupid' => $this->instance->get_group_id(),
261
        ]);
262
        $this->create_log_entries($this->instance, $user->id, 5);
263
        $plugingenerator->create_recording([
264
            'bigbluebuttonbnid' => $this->instance->get_instance_id(),
265
            'groupid' => $this->instance->get_group_id(),
266
            'starttime' => time(),
267
            'endtime' => time() + HOURSECS,
268
        ], true); // Create another recording on the server.
269
 
270
        $this->assertEquals(5, $DB->count_records('bigbluebuttonbn_logs', ['log' => 'Create']));
271
        upgrade_recordings_task::schedule_upgrade_per_meeting();
272
        $this->runAdhocTasks(upgrade_recordings_task::class);
273
        $this->assertEquals(6, recording::count_records(['status' => recording::RECORDING_STATUS_PROCESSED]));
274
        $this->assertEquals(0, $DB->count_records('bigbluebuttonbn_logs', ['log' => 'Create']));
275
        // Ensure that logs match.
276
        $matches = [
277
            'Executing .*',
278
            'Fetching logs for conversion',
279
            "Creating new recording records",
280
            'Migrated 6 recordings',
281
        ];
282
        $this->expectOutputRegex('/' . implode('.*', $matches) . '/s');
283
    }
284
 
285
    /**
286
     * Setup basic data for tests
287
     *
288
     * @param bool $importedrecording
289
     * @return void
290
     * @throws \coding_exception
291
     * @throws \moodle_exception
292
     */
293
    protected function setup_basic_data($importedrecording = false) {
294
        global $DB;
295
        [$teacher, $groups, $instance, $groupedinstance, $deletedinstance] = $this->setup_basic_course_and_meeting();
296
 
297
        $this->create_log_entries($instance, $teacher->id, 30, $importedrecording);
298
        foreach ($groups as $group) {
299
            $groupinstance = instance::get_group_instance_from_instance($groupedinstance, $group->id);
300
            $this->create_log_entries($groupinstance, $teacher->id, 15, $importedrecording);
301
        }
302
        $this->create_log_entries($deletedinstance, $teacher->id, 15, $importedrecording);
303
        course_delete_module($deletedinstance->get_cm_id());
304
        // Truncate the recordings table to reflect what it would have looked like before this version.
305
        $DB->delete_records('bigbluebuttonbn_recordings');
306
        $this->groups = $groups;
307
        $this->instance = $instance;
308
    }
309
 
310
    /**
311
     * Setup basic data for tests
312
     *
313
     * @return array
314
     * @throws \coding_exception
315
     * @throws \moodle_exception
316
     */
317
    protected function setup_basic_course_and_meeting() {
318
        $generator = $this->getDataGenerator();
319
        // Create a course with student and teacher, and two groups.
320
        $this->course = $generator->create_course();
321
        $groups = [];
322
        $groups[] = $generator->create_group(['courseid' => $this->course->id]);
323
        $groups[] = $generator->create_group(['courseid' => $this->course->id]);
324
 
325
        $teacher = $generator->create_and_enrol($this->course, 'editingteacher');
326
        $generator->create_and_enrol($this->course, 'student');
327
 
328
        // Create a "normal" meeting.
329
        $instance = $this->create_meeting_for_logs();
330
        // Create an grouped activity.
331
        $groupedinstance = $this->create_meeting_for_logs($groups);
332
        // Create an instance that will then be deleted.
333
        $deletedinstance = $this->create_meeting_for_logs();
334
        // Create logs for an activity which no longer exists (because we deleted it).
335
        return [$teacher, $groups, $instance, $groupedinstance, $deletedinstance];
336
    }
337
 
338
    /**
339
     * Create a meeting and return its instance
340
     *
341
     * @param array|null $groups
342
     * @return instance
343
     */
344
    protected function create_meeting_for_logs(?array $groups = null) {
345
        $generator = $this->getDataGenerator();
346
        $plugingenerator = $this->getDataGenerator()->get_plugin_generator('mod_bigbluebuttonbn');
347
        $params = [
348
            'course' => $this->course->id,
349
        ];
350
        if (!empty($groups)) {
351
            $params['groupmode'] = SEPARATEGROUPS;
352
        }
353
        $activity = $generator->create_module('bigbluebuttonbn', $params);
354
        $instance = instance::get_from_instanceid($activity->id);
355
        if (!empty($groups)) {
356
            foreach ($groups as $group) {
357
                $groupinstance = instance::get_group_instance_from_instance($instance, $group->id);
358
                $plugingenerator->create_meeting([
359
                    'instanceid' => $groupinstance->get_instance_id(),
360
                    'groupid' => $groupinstance->get_group_id(),
361
                ]);
362
            }
363
        } else {
364
            $plugingenerator->create_meeting([
365
                'instanceid' => $instance->get_instance_id(),
366
                'groupid' => $instance->get_group_id(),
367
            ]);
368
        }
369
        return $instance;
370
    }
371
}