Proyectos de Subversion Moodle

Rev

Rev 1 | | 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
/**
18
 * Meeting test.
19
 *
20
 * @package   mod_bigbluebuttonbn
21
 * @copyright 2018 - present, Blindside Networks Inc
22
 * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
23
 * @author    Jesus Federico  (jesus [at] blindsidenetworks [dt] com)
24
 */
25
 
26
namespace mod_bigbluebuttonbn;
27
 
28
use mod_bigbluebuttonbn\test\testcase_helper_trait;
29
 
30
/**
31
 * Meeting tests class.
32
 *
33
 * @package   mod_bigbluebuttonbn
34
 * @copyright 2018 - present, Blindside Networks Inc
35
 * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
36
 * @author    Jesus Federico  (jesus [at] blindsidenetworks [dt] com)
37
 * @covers \mod_bigbluebuttonbn\meeting
38
 * @coversDefaultClass \mod_bigbluebuttonbn\meeting
39
 */
40
class meeting_test extends \advanced_testcase {
41
    use testcase_helper_trait;
42
 
43
    /**
44
     * Setup Test
45
     */
46
    public function setUp(): void {
47
        parent::setUp();
48
        $this->initialise_mock_server();
49
        // We do not force the group mode so we can change the activity group mode during test.
50
        $this->course = $this->getDataGenerator()->create_course(['groupmode' => SEPARATEGROUPS]);
51
        $this->getDataGenerator()->create_group(['name' => 'G1', 'courseid' => $this->course->id]);
52
        $this->getDataGenerator()->create_group(['name' => 'G2', 'courseid' => $this->course->id]);
53
    }
54
 
55
    /**
56
     * Get a list of possible test (dataprovider)
57
     *
58
     * @return array[]
59
     */
60
    public function get_instance_types_meeting_info(): array {
61
        return [
62
            'Instance Type ALL - No Group' => [
63
                'type' => instance::TYPE_ALL,
64
                'groupname' => null,
65
                'groupmode' => NOGROUPS,
66
                'canjoin' => ['useringroup' => true, 'usernotingroup' => true],
67
            ],
68
            'Instance Type ALL - Group 1 - Visible groups' => [
69
                'type' => instance::TYPE_ALL,
70
                'groupname' => 'G1',
71
                'groupmode' => VISIBLEGROUPS,
72
                'canjoin' => ['useringroup' => true, 'usernotingroup' => true],
73
            ],
74
            'Instance Type ALL - Group 1 - Separate groups' => [
75
                'type' => instance::TYPE_ALL,
76
                'groupname' => 'G1',
77
                'groupmode' => SEPARATEGROUPS,
78
                'canjoin' => ['useringroup' => true, 'usernotingroup' => false],
79
            ],
80
            'Instance Type ROOM Only - No Group' => [
81
                'type' => instance::TYPE_ROOM_ONLY,
82
                'groupname' => null,
83
                'groupmode' => NOGROUPS,
84
                'canjoin' => ['useringroup' => true, 'usernotingroup' => true],
85
            ],
86
            'Instance Type ROOM Only - Group 1 - Visible groups' => [
87
                'type' => instance::TYPE_ROOM_ONLY,
88
                'groupname' => 'G1',
89
                'groupmode' => VISIBLEGROUPS,
90
                'canjoin' => ['useringroup' => true, 'usernotingroup' => true],
91
            ],
92
            'Instance Type ROOM Only - Group 1 - Separate groups' => [
93
                'type' => instance::TYPE_ROOM_ONLY,
94
                'groupname' => 'G1',
95
                'groupmode' => SEPARATEGROUPS,
96
                'canjoin' => ['useringroup' => true, 'usernotingroup' => false],
97
            ],
98
            'Instance Type Recording Only - No Group' => [
99
                'type' => instance::TYPE_RECORDING_ONLY,
100
                'groupname' => null,
101
                'groupmode' => NOGROUPS,
102
                'canjoin' => ['useringroup' => false, 'usernotingroup' => false]
103
            ],
104
            'Instance Type Recording Only - Group 1' => [
105
                'type' => instance::TYPE_RECORDING_ONLY,
106
                'groupname' => 'G1',
107
                'groupmode' => VISIBLEGROUPS,
108
                'canjoin' => ['useringroup' => false, 'usernotingroup' => false]
109
            ]
110
        ];
111
    }
112
 
113
    /**
114
     * Test that create meeing is working for all types.
115
     *
116
     * @dataProvider get_instance_types_meeting_info
117
     * @param int $type
118
     * @param string|null $groupname
119
     * @covers ::create_meeting
120
     * @covers ::create_meeting_data
121
     * @covers ::create_meeting_metadata
122
     */
11 efrain 123
    public function test_create_meeting(int $type, ?string $groupname): void {
1 efrain 124
        $this->resetAfterTest();
125
        [$meeting, $useringroup, $usernotingroup, $groupid, $activity] =
126
            $this->prepare_meeting($type, $groupname, SEPARATEGROUPS, false);
127
        $meeting->create_meeting();
128
        $meetinginfo = $meeting->get_meeting_info();
129
        $this->assertNotNull($meetinginfo);
130
        $this->assertEquals($activity->id, $meetinginfo->bigbluebuttonbnid);
131
        $this->assertFalse($meetinginfo->statusrunning);
132
        $this->assertStringContainsString("is ready", $meetinginfo->statusmessage);
133
        $this->assertEquals($groupid, $meetinginfo->groupid);
134
    }
135
 
136
    /**
137
     * Test for get meeting info for all types
138
     *
139
     * @param int $type
140
     * @param string|null $groupname
141
     * @dataProvider get_instance_types_meeting_info
142
     * @covers ::get_meeting_info
143
     * @covers ::do_get_meeting_info
144
     */
11 efrain 145
    public function test_get_meeting_info(int $type, ?string $groupname): void {
1 efrain 146
        $this->resetAfterTest();
147
        [$meeting, $useringroup, $usernotingroup, $groupid, $activity] = $this->prepare_meeting($type, $groupname);
148
        $meetinginfo = $meeting->get_meeting_info();
149
        $this->assertNotNull($meetinginfo);
150
        $this->assertEquals($activity->id, $meetinginfo->bigbluebuttonbnid);
151
        $this->assertTrue($meetinginfo->statusrunning);
152
        $this->assertStringContainsString("in progress", $meetinginfo->statusmessage);
153
        $this->assertEquals($groupid, $meetinginfo->groupid);
154
        $meeting->end_meeting();
155
        $meeting->update_cache();
156
        $meetinginfo = $meeting->get_meeting_info();
157
        $this->assertFalse($meetinginfo->statusrunning);
158
 
159
        if ($type == instance::TYPE_ALL) {
160
            $this->assertTrue($meetinginfo->features['showroom']);
161
            $this->assertTrue($meetinginfo->features['showrecordings']);
162
        } else if ($type == instance::TYPE_ROOM_ONLY) {
163
            $this->assertTrue($meetinginfo->features['showroom']);
164
            $this->assertFalse($meetinginfo->features['showrecordings']);
165
        } else if ($type == instance::TYPE_RECORDING_ONLY) {
166
            $this->assertFalse($meetinginfo->features['showroom']);
167
            $this->assertTrue($meetinginfo->features['showrecordings']);
168
        }
169
    }
170
 
171
    /**
172
     * Test can join is working for all types
173
     *
174
     * @param int $type
175
     * @param string|null $groupname
176
     * @param int $groupmode
177
     * @param array $canjoin
178
     * @dataProvider get_instance_types_meeting_info
179
     * @covers ::can_join
180
     */
11 efrain 181
    public function test_can_join(int $type, ?string $groupname, int $groupmode, array $canjoin): void {
1 efrain 182
        $this->resetAfterTest();
183
        [$meeting, $useringroup, $usernotingroup, $groupid, $activity] = $this->prepare_meeting($type, $groupname, $groupmode);
184
        $this->setUser($useringroup);
185
        $meeting->update_cache();
186
        $this->assertEquals($canjoin['useringroup'], $meeting->can_join());
187
        if ($meeting->can_join()) {
188
            $meetinginfo = $meeting->get_meeting_info();
189
            $this->assertStringContainsString("The session is in progress.", $meetinginfo->statusmessage);
190
        }
191
        if ($groupname) {
192
            $this->setUser($usernotingroup);
193
            $meeting->update_cache();
194
            $this->assertEquals($canjoin['usernotingroup'], $meeting->can_join());
195
        }
196
    }
197
 
198
    /**
199
     * Test can join is working if opening/closing time are set
200
     *
201
     * @param int $type
202
     * @param string|null $groupname
203
     * @param int $groupmode
204
     * @param array $canjoin
205
     * @param array $dates
206
     * @dataProvider get_data_can_join_with_dates
207
     * @covers ::can_join
208
     */
11 efrain 209
    public function test_can_join_with_dates(int $type, ?string $groupname, int $groupmode, array $canjoin, array $dates): void {
1 efrain 210
        // Apply the data provider relative values to now.
211
        array_walk($dates, function(&$val) {
212
            $val = time() + $val;
213
        });
214
        $this->resetAfterTest();
215
        [$meeting, $useringroup, $usernotingroup, $groupid, $activity] =
216
            $this->prepare_meeting($type, $groupname, $groupmode, true, $dates);
217
        $this->setUser($useringroup);
218
        $meeting->update_cache();
219
        $this->assertEquals($canjoin['useringroup'], $meeting->can_join());
220
        // We check that admin can not join outside opening/closing times either.
221
        $this->setAdminUser();
222
        $this->assertEquals(false, $meeting->can_join());
223
        if ($groupname) {
224
            $this->setUser($usernotingroup);
225
            $meeting->update_cache();
226
            $this->assertEquals($canjoin['usernotingroup'], $meeting->can_join());
227
            $this->setAdminUser();
228
            $this->assertEquals(false, $meeting->can_join());
229
        }
230
    }
231
 
232
    /**
233
     * Test can join is working if the "Wait for moderator to join" setting is set and a moderator has not yet joined.
234
     *
235
     * @covers ::join
236
     * @covers ::join_meeting
237
     */
11 efrain 238
    public function test_join_wait_for_moderator_not_joined(): void {
1 efrain 239
        $this->resetAfterTest();
240
 
241
        $this->setAdminUser();
242
        $bbbgenerator = $this->getDataGenerator()->get_plugin_generator('mod_bigbluebuttonbn');
243
        $student = $this->getDataGenerator()->create_and_enrol($this->get_course());
244
        $meetinginfo = [
245
            'course' => $this->get_course()->id,
246
            'type' => instance::TYPE_ALL,
247
            'wait' => 1,
248
        ];
249
        $activity = $bbbgenerator->create_instance($meetinginfo, [
250
            'wait' => 1,
251
        ]);
252
        $instance = instance::get_from_instanceid($activity->id);
253
        $meeting = new meeting($instance);
254
 
255
        // The moderator has not joined.
256
        $this->setUser($student);
257
        $meeting->update_cache();
258
        $this->expectException(\mod_bigbluebuttonbn\local\exceptions\meeting_join_exception::class);
259
        meeting::join_meeting($instance);
260
    }
261
 
262
    /**
263
     * Test can join is working if the "Wait for moderator to join" setting is set and a moderator has already joined.
264
     *
265
     * @covers ::join
266
     * @covers ::join_meeting
267
     */
11 efrain 268
    public function test_join_wait_for_moderator_is_joined(): void {
1 efrain 269
        $this->resetAfterTest();
270
 
271
        $this->setAdminUser();
272
        $bbbgenerator = $this->getDataGenerator()->get_plugin_generator('mod_bigbluebuttonbn');
273
        $moderator = $this->getDataGenerator()->create_and_enrol($this->get_course(), 'editingteacher');
274
        $student = $this->getDataGenerator()->create_and_enrol($this->get_course());
275
        $meetinginfo = [
276
            'course' => $this->get_course()->id,
277
            'type' => instance::TYPE_ALL,
278
            'wait' => 1,
279
            'moderators' => 'role:editingteacher',
280
        ];
281
        $activity = $bbbgenerator->create_instance($meetinginfo, [
282
            'wait' => 1,
283
        ]);
284
        $instance = instance::get_from_instanceid($activity->id);
285
        $meeting = new meeting($instance);
286
        $bbbgenerator->create_meeting([
287
            'instanceid' => $instance->get_instance_id(),
288
        ]);
289
 
290
        $this->setUser($moderator);
291
        $meeting->update_cache();
292
        $joinurl = $meeting->join(logger::ORIGIN_BASE);
293
        $this->assertIsString($joinurl);
294
        $this->join_meeting($joinurl);
295
        $meeting->update_cache();
296
        $this->assertCount(1, $meeting->get_attendees());
297
 
298
        // The student can now join the meeting as a moderator is present.
299
        $this->setUser($student);
300
        $joinurl = $meeting->join(logger::ORIGIN_BASE);
301
        $this->assertIsString($joinurl);
302
    }
303
 
304
    /**
305
     * Test can join is working if the "user limit" setting is set and reached.
306
     *
307
     * @covers ::join
308
     * @covers ::join_meeting
309
     */
11 efrain 310
    public function test_join_user_limit_reached(): void {
1 efrain 311
        $this->resetAfterTest();
312
        set_config('bigbluebuttonbn_userlimit_editable', true);
313
        $this->setAdminUser();
314
        $bbbgenerator = $this->getDataGenerator()->get_plugin_generator('mod_bigbluebuttonbn');
315
        $moderator = $this->getDataGenerator()->create_and_enrol($this->get_course(), 'editingteacher');
316
        $student1 = $this->getDataGenerator()->create_and_enrol($this->get_course());
317
        $student2 = $this->getDataGenerator()->create_and_enrol($this->get_course());
318
        $meetinginfo = [
319
            'course' => $this->get_course()->id,
320
            'type' => instance::TYPE_ALL,
321
            'userlimit' => 2,
322
        ];
323
        $activity = $bbbgenerator->create_instance($meetinginfo, [
324
            'userlimit' => 2,
325
        ]);
326
        $instance = instance::get_from_instanceid($activity->id);
327
        $meeting = new meeting($instance);
328
        $bbbgenerator->create_meeting([
329
            'instanceid' => $instance->get_instance_id(),
330
        ]);
331
        // Moderator joins the meeting.
332
        $this->setUser($moderator);
333
        $this->join_meeting($meeting->join(logger::ORIGIN_BASE));
334
        $meeting->update_cache();
335
        $this->assertEquals(1, $meeting->get_participant_count());
336
 
337
        // Student1 joins the meeting.
338
        $this->setUser($student1);
339
        $this->join_meeting($meeting->join(logger::ORIGIN_BASE));
340
        $meeting->update_cache();
341
        $this->assertEquals(2, $meeting->get_participant_count());
342
        $this->assertTrue($instance->has_user_limit_been_reached($meeting->get_participant_count()));
343
 
344
        // Student2 tries to join but the limit has been reached.
345
        $this->setUser($student2);
346
        $meeting->update_cache();
347
        $this->assertFalse($meeting->can_join());
348
        $this->expectException(\mod_bigbluebuttonbn\local\exceptions\meeting_join_exception::class);
349
        meeting::join_meeting($instance);
350
    }
351
 
352
    /**
353
     * Test that attendees returns the right list of attendees
354
     *
355
     * @covers ::get_attendees
356
     */
11 efrain 357
    public function test_get_attendees(): void {
1 efrain 358
        $this->resetAfterTest();
359
        [$meeting, $useringroup, $usernotingroup, $groupid, $activity] =
360
            $this->prepare_meeting(instance::TYPE_ALL, null, NOGROUPS, true);
361
        $this->setUser($useringroup);
362
        $this->join_meeting($meeting->join(logger::ORIGIN_BASE));
363
        $meeting->update_cache();
364
        $this->assertCount(1, $meeting->get_attendees());
365
        $otheruser = $this->getDataGenerator()->create_and_enrol($this->get_course());
366
        $this->setUser($otheruser);
367
        $meeting->update_cache();
368
        $this->join_meeting($meeting->join(logger::ORIGIN_BASE));
369
        $meeting->update_cache();
370
        $this->assertCount(2, $meeting->get_attendees());
371
    }
372
 
373
    /**
374
     * Test that attendees returns the right list of attendees
375
     *
376
     * @covers ::get_attendees
377
     */
11 efrain 378
    public function test_participant_count(): void {
1 efrain 379
        $this->resetAfterTest();
380
        [$meeting, $useringroup, $usernotingroup, $groupid, $activity] =
381
            $this->prepare_meeting(instance::TYPE_ALL, null, NOGROUPS, true);
382
        $this->setUser($useringroup);
383
        $this->join_meeting($meeting->join(logger::ORIGIN_BASE));
384
        $meeting->update_cache();
385
        $meetinginfo = $meeting->get_meeting_info();
386
        $this->assertEquals(1, $meetinginfo->participantcount);
387
        $this->assertEquals(1, $meetinginfo->totalusercount);
388
        $this->assertEquals(0, $meetinginfo->moderatorcount);
389
        $this->setUser($usernotingroup);
390
        $this->join_meeting($meeting->join(logger::ORIGIN_BASE));
391
        $meeting->update_cache();
392
        $meetinginfo = $meeting->get_meeting_info();
393
        $this->assertEquals(2, $meetinginfo->participantcount);
394
        $this->assertEquals(2, $meetinginfo->totalusercount);
395
        $this->assertEquals(0, $meetinginfo->moderatorcount);
396
        $this->setAdminUser();
397
        $this->join_meeting($meeting->join(logger::ORIGIN_BASE));
398
        $meeting->update_cache();
399
        $meetinginfo = $meeting->get_meeting_info();
400
        $this->assertEquals(2, $meetinginfo->participantcount);
401
        $this->assertEquals(3, $meetinginfo->totalusercount);
402
        $this->assertEquals(1, $meetinginfo->moderatorcount);
403
    }
404
    /**
405
     * Send a join meeting API CALL
406
     *
407
     * @param string $url
408
     */
409
    protected function join_meeting(string $url) {
410
        $curl = new \curl();
411
        $url = new \moodle_url($url);
412
        $curl->get($url->out_omit_querystring(), $url->params());
413
    }
414
 
415
    /**
416
     * Get a list of possible test (dataprovider)
417
     *
418
     * @return array[]
419
     */
420
    public function get_data_can_join_with_dates(): array {
421
        return [
422
            'Instance Type ALL - No Group - Closed in past' => [
423
                'type' => instance::TYPE_ALL,
424
                'groupname' => null,
425
                'groupmode' => NOGROUPS,
426
                'canjoin' => ['useringroup' => false, 'usernotingroup' => false],
427
                'dates' => ['openingtime' => -7200, 'closingtime' => -3600]
428
            ],
429
            'Instance Type ALL - No Group - Open in future' => [
430
                'type' => instance::TYPE_ALL,
431
                'groupname' => null,
432
                'groupmode' => NOGROUPS,
433
                'canjoin' => ['useringroup' => false, 'usernotingroup' => false],
434
                'dates' => ['openingtime' => 3600, 'closingtime' => 7200]
435
            ],
436
        ];
437
    }
438
 
439
    /**
440
     * Helper to prepare for a meeting
441
     *
442
     * @param int $type
443
     * @param string|null $groupname
444
     * @param int $groupmode
445
     * @param bool $createmeeting
446
     * @param array $dates
447
     * @return array
448
     */
449
    protected function prepare_meeting(int $type, ?string $groupname, int $groupmode = SEPARATEGROUPS, bool $createmeeting = true,
450
        array $dates = []) {
451
        $this->setAdminUser();
452
        $bbbgenerator = $this->getDataGenerator()->get_plugin_generator('mod_bigbluebuttonbn');
453
        $groupid = 0;
454
        $useringroup = $this->getDataGenerator()->create_and_enrol($this->get_course());
455
        $usernotingroup = $this->getDataGenerator()->create_and_enrol($this->get_course());
456
        if (!empty($groupname)) {
457
            $groupid = groups_get_group_by_name($this->get_course()->id, $groupname);
458
            $this->getDataGenerator()->create_group_member(['groupid' => $groupid, 'userid' => $useringroup->id]);
459
        }
460
        $meetinginfo = [
461
            'course' => $this->get_course()->id,
462
            'type' => $type
463
        ];
464
        if ($dates) {
465
            $meetinginfo = array_merge($meetinginfo, $dates);
466
        };
467
        $activity = $bbbgenerator->create_instance($meetinginfo, ['groupmode' => $groupmode]);
468
        $instance = instance::get_from_instanceid($activity->id);
469
        if ($groupid) {
470
            $instance->set_group_id($groupid);
471
        }
472
        if ($createmeeting) {
473
            // Create the meetings on the mock server, so we can join it as a simple user.
474
            $bbbgenerator->create_meeting([
475
                'instanceid' => $instance->get_instance_id(),
476
                'groupid' => $instance->get_group_id()
477
            ]);
478
        }
479
        $meeting = new meeting($instance);
480
        return [$meeting, $useringroup, $usernotingroup, $groupid, $activity];
481
    }
482
}