See Release Notes
Long Term Support Release
Differences Between: [Versions 400 and 401]
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 */ 123 public function test_create_meeting(int $type, ?string $groupname) { 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 */ 145 public function test_get_meeting_info(int $type, ?string $groupname) { 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 */ 181 public function test_can_join(int $type, ?string $groupname, int $groupmode, array $canjoin) { 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 */ 209 public function test_can_join_with_dates(int $type, ?string $groupname, int $groupmode, array $canjoin, array $dates) { 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 */ 238 public function test_join_wait_for_moderator_not_joined() { 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 */ 268 public function test_join_wait_for_moderator_is_joined() { 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 */ 310 public function test_join_user_limit_reached() { 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 */ 357 public function test_get_attendees() { 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 */ 378 public function test_participant_count() { 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 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body