first commit

This commit is contained in:
CHIEFSOFT\ameye
2024-09-30 18:11:26 -04:00
commit e592ca6823
27270 changed files with 5002257 additions and 0 deletions
@@ -0,0 +1,92 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
namespace mod_bigbluebuttonbn\task;
use advanced_testcase;
/**
* Class containing the scheduled task for lti module.
*
* @package mod_bigbluebuttonbn
* @copyright 2023 onwards, Blindside Networks Inc
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @covers \mod_bigbluebuttonbn\task\base_send_notification
* @coversDefaultClass \mod_bigbluebuttonbn\task\base_send_notification
*/
class base_send_notification_test extends advanced_testcase {
/**
* Returns mock base_send_notification class
*
* @return base_send_notification
*/
private function get_mock(): base_send_notification {
return $this->getMockForAbstractClass(
base_send_notification::class,
[],
'',
true,
true,
true,
[]
);
}
/**
* Returns reflection method for base_send_notification->get_instance
*
* @return \ReflectionMethod
*/
private function get_instance_reflection(): \ReflectionMethod {
$rc = new \ReflectionClass(base_send_notification::class);
return $rc->getMethod('get_instance');
}
/**
* Check if set instance ID works correctly
*/
public function test_set_instance_id(): void {
$this->resetAfterTest();
$stub = $this->get_mock();
$generator = $this->getDataGenerator();
$course = $generator->create_course();
$instancedata = $generator->create_module('bigbluebuttonbn', [
'course' => $course->id,
]);
$stub->set_instance_id($instancedata->id);
$rcm = $this->get_instance_reflection();
$instance = $rcm->invoke($stub);
$this->assertNotNull($instance);
$this->assertEquals($instancedata->id, $instance->get_instance_id());
}
/**
* Check if instanceid missing is checked and handled.
*/
public function test_set_instanceid_missing(): void {
$this->resetAfterTest();
$stub = $this->get_mock();
$rcm = $this->get_instance_reflection();
// This should throw a coding exception since there is no instanceid set.
$this->expectException(\coding_exception::class);
$this->expectExceptionMessage("Task custom data was missing instanceid");
$rcm->invoke($stub);
}
}
@@ -0,0 +1,117 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
namespace mod_bigbluebuttonbn\task;
use advanced_testcase;
use mod_bigbluebuttonbn\instance;
use mod_bigbluebuttonbn\recording;
use mod_bigbluebuttonbn\test\testcase_helper_trait;
/**
* Test class for the check_pending_recordings and check_dismissed_recordings task
*
* @package mod_bigbluebuttonbn
* @copyright 2022 onwards, Blindside Networks Inc
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @covers \mod_bigbluebuttonbn\task\check_dismissed_recordings
* @covers \mod_bigbluebuttonbn\task\check_pending_recordings
* @covers \mod_bigbluebuttonbn\recording::sync_pending_recordings_from_server
*/
class check_recordings_task_test extends advanced_testcase {
use testcase_helper_trait;
/**
* @var $RECORDINGS_DATA array fake recording data.
*/
const RECORDINGS_DATA = [
['name' => 'Recording 1'],
['name' => 'Recording 2'],
['name' => 'Recording 3'],
['name' => 'Recording 4'],
];
/**
* Setup for test
*/
public function setUp(): void {
parent::setUp();
$this->initialise_mock_server();
$this->resetAfterTest();
}
/**
* Test that dismissed recordings are retrieved
*/
public function test_check_dismissed_recordings(): void {
$this->create_meeting_and_recordings(recording::RECORDING_STATUS_DISMISSED);
$this->assertEquals(4, recording::count_records());
$this->assertEquals(0, recording::count_records(['status' => recording::RECORDING_STATUS_PROCESSED]));
$task = new check_dismissed_recordings();
ob_start();
$task->execute();
ob_end_clean();
$this->assertEquals(4, recording::count_records(['status' => recording::RECORDING_STATUS_PROCESSED]));
}
/**
* Test that pending recordings are retrieved
*/
public function test_check_pending_recordings(): void {
$this->create_meeting_and_recordings();
$this->assertEquals(4, recording::count_records());
$this->assertEquals(0, recording::count_records(['status' => recording::RECORDING_STATUS_PROCESSED]));
$task = new check_pending_recordings();
ob_start();
$task->execute();
ob_end_clean();
$this->assertEquals(4, recording::count_records(['status' => recording::RECORDING_STATUS_PROCESSED]));
}
/**
* Create sample meeting and recording.
*
* @param int $status status for the newly created recordings
* @return array recording data (not the persistent class but plain object)
*/
private function create_meeting_and_recordings(int $status = recording::RECORDING_STATUS_AWAITING): array {
$generator = $this->getDataGenerator()->get_plugin_generator('mod_bigbluebuttonbn');
$course = $this->getDataGenerator()->create_course();
$activity = $generator->create_instance([
'course' => $course->id,
'type' => instance::TYPE_ALL
]);
$instance = instance::get_from_instanceid($activity->id);
$generator->create_meeting([
'instanceid' => $instance->get_instance_id(),
'groupid' => $instance->get_group_id()
]);
foreach (self::RECORDINGS_DATA as $data) {
$rdata = $generator->create_recording(
array_merge([
'bigbluebuttonbnid' => $instance->get_instance_id(),
'groupid' => $instance->get_group_id()
], $data)
);
$recording = new recording($rdata->id);
$recording->set('status', $status);
$recording->save();
$recordings[] = $rdata;
}
return $recordings;
}
}
@@ -0,0 +1,122 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
namespace mod_bigbluebuttonbn\task;
use advanced_testcase;
use mod_bigbluebuttonbn\task\completion_update_state;
/**
* Completion_update_state task tests.
*
* @package mod_bigbluebuttonbn
* @copyright 2024 Catalyst IT
* @author Matthew Hilton <matthewhilton@catalyst-au.net>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @covers \mod_bigbluebuttonbn\task\completion_update_state
*/
final class completion_update_state_task_test extends advanced_testcase {
/**
* Providers data to test_invalid_customdata test
* @return array
*/
public static function invalid_customdata_provider(): array {
return [
'empty' => [
'customdata' => [],
'expectoutput' => "",
'expectexceptionmessage' => "Task customdata was missing bigbluebuttonbn->id or userid",
],
'bbb id set but is invalid' => [
'customdata' => [
'bigbluebuttonbn' => -1,
],
'expectoutput' => "",
'expectexceptionmessage' => "Task customdata was missing bigbluebuttonbn->id or userid",
],
'bbb id is valid, but there is no user' => [
'customdata' => [
'bigbluebuttonbn' => ':bbb',
],
'expectoutput' => "",
'expectexceptionmessage' => "Task customdata was missing bigbluebuttonbn->id or userid",
],
'bbb id is valid, but the user is not given' => [
'customdata' => [
'bigbluebuttonbn' => ':bbb',
],
'expectoutput' => "",
'expectexceptionmessage' => "Task customdata was missing bigbluebuttonbn->id or userid",
],
'bbb id is valid, but the user given is invalid' => [
'customdata' => [
'bigbluebuttonbn' => ':bbb',
'userid' => -1,
],
'expectoutput' => "User does not exist, ignoring.\n",
'expectexceptionmessage' => "",
],
'bbb and userid is valid' => [
'customdata' => [
'bigbluebuttonbn' => ':bbb',
'userid' => ':userid',
],
// Expects this output, since all the necessary data is there.
'expectoutput' => "Task completion_update_state running for user :userid\nCompletion not enabled\n",
'expectexceptionmessage' => "",
],
];
}
/**
* Tests the task handles an invalid cmid gracefully.
* @param array $customdata customdata to set (with placeholders to replace with real data).
* @param string $expectoutput any output expected from the test, or empty to not expect output.
* @param string $expectexceptionmessage exception message expected from test, or empty to expect nothing.
* @dataProvider invalid_customdata_provider
*/
public function test_invalid_customdata(array $customdata, string $expectoutput, string $expectexceptionmessage): void {
$this->resetAfterTest();
$customdata = (object) $customdata;
// Replace any placeholders in the customdata.
if (!empty($customdata->bigbluebuttonbn) && $customdata->bigbluebuttonbn == ':bbb') {
$course = $this->getDataGenerator()->create_course();
$module = $this->getDataGenerator()->create_module('bigbluebuttonbn', ['course' => $course->id]);
$customdata->bigbluebuttonbn = $module;
}
$user = $this->getDataGenerator()->create_user();
// Replace userid placeholders.
if (!empty($customdata->userid) && $customdata->userid == ':userid') {
$customdata->userid = $user->id;
}
$task = new completion_update_state();
$task->set_custom_data($customdata);
if (!empty($expectoutput)) {
$expectoutput = str_replace(':userid', $user->id, $expectoutput);
$this->expectOutputString($expectoutput);
}
if (!empty($expectexceptionmessage)) {
$this->expectExceptionMessage($expectexceptionmessage);
}
$task->execute();
}
}
@@ -0,0 +1,66 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
namespace mod_bigbluebuttonbn\task;
use advanced_testcase;
/**
* Send guest email tests
*
* @package mod_bigbluebuttonbn
* @copyright 2019 onwards, Blindside Networks Inc
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @covers \mod_bigbluebuttonbn\task\send_guest_emails
* @coversDefaultClass \mod_bigbluebuttonbn\task\send_guest_emails
*/
class send_guest_emails_test extends advanced_testcase {
/**
* Check if set instance ID works correctly
*
*/
public function test_send_emails(): void {
$this->resetAfterTest();
$emailsink = $this->redirectEmails();
$generator = $this->getDataGenerator();
$course = $generator->create_course();
$instancedata = $generator->create_module('bigbluebuttonbn', [
'course' => $course->id,
]);
$moderatoruser = $generator->create_user();
$guestemail = new send_guest_emails();
$guestemail->set_custom_data(
[
'emails' => ['test1@email.com', 'test2@email.com'],
'useridfrom' => $moderatoruser->id
]
);
$guestemail->set_instance_id($instancedata->id);
\core\task\manager::queue_adhoc_task($guestemail);
$this->runAdhocTasks();
// Check the events.
$messages = $emailsink->get_messages();
$this->assertCount(2, $messages);
$this->assertEquals('Invitation: BigBlueButton 1 session in Test course 1', $messages[0]->subject);
$this->assertEquals('noreply@www.example.com', $messages[0]->from);
$this->assertEquals('test1@email.com', $messages[0]->to);
$this->assertEquals('test2@email.com', $messages[1]->to);
}
}
@@ -0,0 +1,41 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
namespace mod_bigbluebuttonbn\task;
use advanced_testcase;
/**
* Class containing the scheduled task for lti module.
*
* @package mod_bigbluebuttonbn
* @copyright 2019 onwards, Blindside Networks Inc
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @covers \mod_bigbluebuttonbn\task\send_notification
* @coversDefaultClass \mod_bigbluebuttonbn\task\send_notification
*/
class send_notification_test extends advanced_testcase {
/**
* Test that the debug message is correctly output.
*
*/
public function test_generate_message(): void {
$this->resetAfterTest();
$task = new send_notification();
$message = $task->generate_message();
$this->assertEquals("Attempted to run deprecated implementation of send_notification task.", $message);
}
}
@@ -0,0 +1,194 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
namespace mod_bigbluebuttonbn\task;
use advanced_testcase;
/**
* Class containing the scheduled task for lti module.
*
* @package mod_bigbluebuttonbn
* @copyright 2019 onwards, Blindside Networks Inc
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @coversDefaultClass \mod_bigbluebuttonbn\task\base_send_notification
* @covers \mod_bigbluebuttonbn\task\base_send_notification
* @covers \mod_bigbluebuttonbn\task\send_recording_ready_notification
*/
class send_recording_ready_notification_test extends advanced_testcase {
/**
* Test the sending of messages.
*/
public function test_recipients(): void {
$this->resetAfterTest();
$this->preventResetByRollback();
$generator = $this->getDataGenerator();
$course = $generator->create_course();
$instancedata = $generator->create_module('bigbluebuttonbn', [
'course' => $course->id,
]);
// Create some users in the course, and some not.
$editingteacher = $generator->create_and_enrol($course, 'editingteacher');
$teacher = $generator->create_and_enrol($course, 'teacher');
$students = [
$generator->create_and_enrol($course, 'student'),
$generator->create_and_enrol($course, 'student'),
$generator->create_and_enrol($course, 'student'),
$generator->create_and_enrol($course, 'student'),
$generator->create_and_enrol($course, 'student'),
];
$recipients = array_map(function($user) {
return $user->id;
}, $students);
$recipients[] = $editingteacher->id;
$recipients[] = $teacher->id;
$unrelateduser = $generator->create_user();
$instancedata = $generator->create_module('bigbluebuttonbn', [
'course' => $course->id,
]);
$stub = $this->getMockBuilder(send_recording_ready_notification::class)
->onlyMethods([])
->getMock();
$stub->set_instance_id($instancedata->id);
// Capture events.
$sink = $this->redirectMessages();
// Now execute.
$stub->execute();
// Check the events.
$messages = $sink->get_messages();
$this->assertCount(7, $messages);
foreach ($messages as $message) {
$this->assertNotFalse(array_search($message->useridto, $recipients));
$this->assertNotEquals($unrelateduser->id, $message->useridto);
$this->assertEquals($editingteacher->id, $message->useridfrom);
}
}
/**
* Test the sending of messages.
*/
public function test_recipients_no_teacher(): void {
$this->resetAfterTest();
$this->preventResetByRollback();
$generator = $this->getDataGenerator();
$course = $generator->create_course();
$instancedata = $generator->create_module('bigbluebuttonbn', [
'course' => $course->id,
]);
// Create some users in the course, and some not.
$students = [
$generator->create_and_enrol($course, 'student'),
$generator->create_and_enrol($course, 'student'),
$generator->create_and_enrol($course, 'student'),
$generator->create_and_enrol($course, 'student'),
$generator->create_and_enrol($course, 'student'),
];
$recipients = array_map(function($user) {
return $user->id;
}, $students);
$unrelateduser = $generator->create_user();
$instancedata = $generator->create_module('bigbluebuttonbn', [
'course' => $course->id,
]);
$stub = $this->getMockBuilder(send_recording_ready_notification::class)
->onlyMethods([])
->getMock();
$stub->set_instance_id($instancedata->id);
// Capture events.
$sink = $this->redirectMessages();
// Now execute.
$stub->execute();
// Check the events.
$messages = $sink->get_messages();
$this->assertCount(5, $messages);
$noreplyuser = \core_user::get_noreply_user();
foreach ($messages as $message) {
$this->assertNotFalse(array_search($message->useridto, $recipients));
$this->assertNotEquals($unrelateduser->id, $message->useridto);
$this->assertEquals($noreplyuser->id, $message->useridfrom);
}
}
/**
* Test that messages are not sent to a suspended user.
*/
public function test_messages_sent_suspended_user(): void {
global $DB;
$this->resetAfterTest();
$this->preventResetByRollback();
$generator = $this->getDataGenerator();
$course = $generator->create_course();
$instancedata = $generator->create_module('bigbluebuttonbn', [
'course' => $course->id,
]);
// Create some users in the course, and some not.
$student = $generator->create_and_enrol($course, 'student');
$suspendedstudent = $generator->create_and_enrol($course, 'student');
$DB->set_field('user', 'suspended', 1, ['id' => $suspendedstudent->id]);
$instancedata = $generator->create_module('bigbluebuttonbn', [
'course' => $course->id,
]);
$stub = $this->getMockBuilder(send_recording_ready_notification::class)
->onlyMethods([])
->getMock();
$stub->set_instance_id($instancedata->id);
// Capture events.
$sink = $this->redirectMessages();
// Now execute.
$stub->execute();
// Check the events.
$messages = $sink->get_messages();
$this->assertCount(1, $messages);
$noreplyuser = \core_user::get_noreply_user();
foreach ($messages as $message) {
$this->assertEquals($student->id, $message->useridto);
$this->assertNotEquals($suspendedstudent->id, $message->useridto);
$this->assertEquals($noreplyuser->id, $message->useridfrom);
}
}
}
@@ -0,0 +1,371 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
namespace mod_bigbluebuttonbn\task;
use advanced_testcase;
use core\task\manager;
use mod_bigbluebuttonbn\instance;
use mod_bigbluebuttonbn\logger;
use mod_bigbluebuttonbn\recording;
use mod_bigbluebuttonbn\test\testcase_helper_trait;
/**
* Class containing the scheduled task for lti module.
*
* @package mod_bigbluebuttonbn
* @copyright 2019 onwards, Blindside Networks Inc
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @covers \mod_bigbluebuttonbn\task\upgrade_recordings_task
*/
class upgrade_recordings_task_test extends advanced_testcase {
use testcase_helper_trait;
/**
* @var object $instance
*/
protected $instance = null;
/**
* @var array $groups all groups
*/
protected $groups = [];
/**
* Setup for test
*/
public function setUp(): void {
parent::setUp();
$this->initialise_mock_server();
$this->resetAfterTest();
}
/**
* Upgrade task test
*/
public function test_upgrade_recordings_basic(): void {
global $DB;
$this->setup_basic_data();
upgrade_recordings_task::schedule_upgrade_per_meeting(false);;
// The first run will lead to all of them being processed, and none left over.
// A new job is always queued on a successful run.
$this->runAdhocTasks(upgrade_recordings_task::class);
$this->assertEquals(0, $DB->count_records('bigbluebuttonbn_logs', ['log' => logger::EVENT_CREATE]));
$this->assertEquals(75, recording::count_records(['imported' => '0']));
// Old logs are kept but renamed.
$this->assertEquals(75, $DB->count_records('bigbluebuttonbn_logs', ['log' => logger::EVENT_CREATE_MIGRATED]));
$this->assertEquals(15, recording::count_records(['groupid' => $this->groups[0]->id, 'imported' => '0',
'status' => recording::RECORDING_STATUS_PROCESSED]));
$this->assertEquals(15, recording::count_records(['groupid' => $this->groups[1]->id, 'imported' => '0',
'status' => recording::RECORDING_STATUS_PROCESSED]));
$this->assertEquals(45,
recording::count_records(['groupid' => 0, 'imported' => '0', 'status' => recording::RECORDING_STATUS_PROCESSED]));
// The second run will lead to no change in the number of logs, but no further jobs will be queued.
upgrade_recordings_task::schedule_upgrade_per_meeting();
$this->runAdhocTasks(upgrade_recordings_task::class);
$this->assertEquals(75, recording::count_records());
// The first run will lead to all of them being processed, and none left over.
// A new job is always queued on a successful run.
$this->assertEmpty($DB->get_records_select(
'bigbluebuttonbn_logs',
'log = :logmatch AND ' . $DB->sql_like('meta', ':match'),
[
'logmatch' => 'Create',
'match' => '%true%'
]
));
$this->runAdhocTasks(upgrade_recordings_task::class);
$this->assertEmpty($DB->get_records_select(
'bigbluebuttonbn_logs',
'log = :logmatch AND ' . $DB->sql_like('meta', ':match'),
[
'logmatch' => 'Create',
'match' => '%true%'
]
));
$this->assertEquals(0, $DB->count_records('bigbluebuttonbn_logs', ['log' => 'Create']));
// Ensure that logs match.
$matchesarray = [
[
'Executing .*',
'Fetching logs for conversion',
"Creating new recording records",
'Migrated 30 recordings',
],
[
'Executing .*',
'Fetching logs for conversion',
"Creating new recording records",
'Migrated 15 recordings',
],
[
'Executing .*',
'Fetching logs for conversion',
"Creating new recording records",
"Unable to find an activity for .*. This recording is headless",
'Migrated 15 recordings'
]
];
foreach ($matchesarray as $matches) {
$this->expectOutputRegex('/' . implode('.*', $matches) . '/s');
}
$this->resetDebugging(); // We might have debugging message that are sent by get_from_meetingid and can ignore them.
}
/**
* Upgrade task test
*/
public function test_upgrade_recordings_imported_basic(): void {
global $DB;
$this->setup_basic_data(true);
upgrade_recordings_task::schedule_upgrade_per_meeting(true);;
// The first run will lead to all of them being processed, and none left over.
// A new job is always queued on a successful run.
$this->runAdhocTasks(upgrade_recordings_task::class);
$this->assertEquals(0, $DB->count_records('bigbluebuttonbn_logs', ['log' => logger::EVENT_IMPORT]));
$this->assertEquals(75, $DB->count_records('bigbluebuttonbn_logs', ['log' => logger::EVENT_IMPORT_MIGRATED]));
$this->assertEquals(75, recording::count_records(['imported' => '1']));
$this->assertEquals(15, recording::count_records(['groupid' => $this->groups[0]->id, 'imported' => '1',
'status' => recording::RECORDING_STATUS_PROCESSED]));
$this->assertEquals(15, recording::count_records(['groupid' => $this->groups[1]->id, 'imported' => '1',
'status' => recording::RECORDING_STATUS_PROCESSED]));
$this->assertEquals(45,
recording::count_records(['groupid' => 0, 'imported' => '1', 'status' => recording::RECORDING_STATUS_PROCESSED]));
// The second run will lead to no change in the number of logs, but no further jobs will be queued.
upgrade_recordings_task::schedule_upgrade_per_meeting();
$this->runAdhocTasks(upgrade_recordings_task::class);
$this->assertEquals(75, recording::count_records(['imported' => '1']));
// The first run will lead to all of them being processed, and none left over.
// A new job is always queued on a successful run.
$this->assertEmpty($DB->get_records_select(
'bigbluebuttonbn_logs',
'log = :logmatch',
[
'logmatch' => 'Import'
]
));
// Ensure that logs match.
$matchesarray = [
[
'Executing .*',
'Fetching logs for conversion',
"Creating new recording records",
'Migrated 30 recordings',
],
[
'Executing .*',
'Fetching logs for conversion',
"Creating new recording records",
'Migrated 15 recordings',
],
[
'Executing .*',
'Fetching logs for conversion',
"Creating new recording records",
"Unable to find an activity for .*. This recording is headless",
'Migrated 15 recordings'
]
];
foreach ($matchesarray as $matches) {
$this->expectOutputRegex('/' . implode('.*', $matches) . '/s');
}
$this->resetDebugging(); // We might have debugging message that are sent by get_from_meetingid and can ignore them.
}
/**
* Upgrade recordings when we have missing recordings on the server
* Basically, the recordings are imported and then we cannot the other because logs have been marked as migrated.
*/
public function test_upgrade_recordings_with_missing_recording_on_bbb_server(): void {
global $DB;
$plugingenerator = $this->getDataGenerator()->get_plugin_generator('mod_bigbluebuttonbn');
[$teacher, $groups, $instance, $groupedinstance, $deletedinstance] = $this->setup_basic_course_and_meeting();
$this->create_log_entries($instance, $teacher->id, 5);
$this->create_log_entries($instance, $teacher->id, 5, false, false);
$this->assertEquals(10, $DB->count_records('bigbluebuttonbn_logs', ['log' => 'Create']));
// Schedule the run.
upgrade_recordings_task::schedule_upgrade_per_meeting();
$this->runAdhocTasks(upgrade_recordings_task::class);
// At this point only 5 are created, the rest is still in the queue.
$this->assertEquals(0, $DB->count_records('bigbluebuttonbn_logs', ['log' => 'Create']));
$this->assertEquals(5, recording::count_records());
// Now create 5 recordings on the server.
// Schedule the run.
upgrade_recordings_task::schedule_upgrade_per_meeting();
for ($index = 0; $index < 5; $index++) {
$plugingenerator->create_recording([
'bigbluebuttonbnid' => $instance->get_instance_id(),
'groupid' => $instance->get_group_id(),
'starttime' => time(),
'endtime' => time() + HOURSECS,
], true); // Create another recording on the server.
}
$this->assertEquals(0, $DB->count_records('task_adhoc', ['classname' => '\\' . upgrade_recordings_task::class]));
$this->runAdhocTasks(upgrade_recordings_task::class);
// Ensure that logs match.
// Ensure that logs match.
$matchesarray = [
[
'Executing .*',
'Fetching logs for conversion',
"Creating new recording records",
'Migrated 5 recordings',
],
];
foreach ($matchesarray as $matches) {
$this->expectOutputRegex('/' . implode('.*', $matches) . '/s');
}
}
/**
* Upgrade task test with more recordings on the server than in the log : we add all recording and should have
* no more logs.
*/
public function test_upgrade_recordings_with_more_recordings_on_bbb_server(): void {
global $DB;
$generator = $this->getDataGenerator();
// Create a course with student and teacher, and two groups.
$this->course = $generator->create_course();
$user = $this->getDataGenerator()->create_and_enrol($this->course);
// Create an ungrouped activity.
$activity = $generator->create_module('bigbluebuttonbn', [
'course' => $this->course->id,
]);
$this->instance = instance::get_from_instanceid($activity->id);
// We create 5 recordings in the log but no recording instance on the server.
$plugingenerator = $this->getDataGenerator()->get_plugin_generator('mod_bigbluebuttonbn');
$plugingenerator->create_meeting([
'instanceid' => $this->instance->get_instance_id(),
'groupid' => $this->instance->get_group_id(),
]);
$this->create_log_entries($this->instance, $user->id, 5);
$plugingenerator->create_recording([
'bigbluebuttonbnid' => $this->instance->get_instance_id(),
'groupid' => $this->instance->get_group_id(),
'starttime' => time(),
'endtime' => time() + HOURSECS,
], true); // Create another recording on the server.
$this->assertEquals(5, $DB->count_records('bigbluebuttonbn_logs', ['log' => 'Create']));
upgrade_recordings_task::schedule_upgrade_per_meeting();
$this->runAdhocTasks(upgrade_recordings_task::class);
$this->assertEquals(6, recording::count_records(['status' => recording::RECORDING_STATUS_PROCESSED]));
$this->assertEquals(0, $DB->count_records('bigbluebuttonbn_logs', ['log' => 'Create']));
// Ensure that logs match.
$matches = [
'Executing .*',
'Fetching logs for conversion',
"Creating new recording records",
'Migrated 6 recordings',
];
$this->expectOutputRegex('/' . implode('.*', $matches) . '/s');
}
/**
* Setup basic data for tests
*
* @param bool $importedrecording
* @return void
* @throws \coding_exception
* @throws \moodle_exception
*/
protected function setup_basic_data($importedrecording = false) {
global $DB;
[$teacher, $groups, $instance, $groupedinstance, $deletedinstance] = $this->setup_basic_course_and_meeting();
$this->create_log_entries($instance, $teacher->id, 30, $importedrecording);
foreach ($groups as $group) {
$groupinstance = instance::get_group_instance_from_instance($groupedinstance, $group->id);
$this->create_log_entries($groupinstance, $teacher->id, 15, $importedrecording);
}
$this->create_log_entries($deletedinstance, $teacher->id, 15, $importedrecording);
course_delete_module($deletedinstance->get_cm_id());
// Truncate the recordings table to reflect what it would have looked like before this version.
$DB->delete_records('bigbluebuttonbn_recordings');
$this->groups = $groups;
$this->instance = $instance;
}
/**
* Setup basic data for tests
*
* @return array
* @throws \coding_exception
* @throws \moodle_exception
*/
protected function setup_basic_course_and_meeting() {
$generator = $this->getDataGenerator();
// Create a course with student and teacher, and two groups.
$this->course = $generator->create_course();
$groups = [];
$groups[] = $generator->create_group(['courseid' => $this->course->id]);
$groups[] = $generator->create_group(['courseid' => $this->course->id]);
$teacher = $generator->create_and_enrol($this->course, 'editingteacher');
$generator->create_and_enrol($this->course, 'student');
// Create a "normal" meeting.
$instance = $this->create_meeting_for_logs();
// Create an grouped activity.
$groupedinstance = $this->create_meeting_for_logs($groups);
// Create an instance that will then be deleted.
$deletedinstance = $this->create_meeting_for_logs();
// Create logs for an activity which no longer exists (because we deleted it).
return [$teacher, $groups, $instance, $groupedinstance, $deletedinstance];
}
/**
* Create a meeting and return its instance
*
* @param array|null $groups
* @return instance
*/
protected function create_meeting_for_logs(?array $groups = null) {
$generator = $this->getDataGenerator();
$plugingenerator = $this->getDataGenerator()->get_plugin_generator('mod_bigbluebuttonbn');
$params = [
'course' => $this->course->id,
];
if (!empty($groups)) {
$params['groupmode'] = SEPARATEGROUPS;
}
$activity = $generator->create_module('bigbluebuttonbn', $params);
$instance = instance::get_from_instanceid($activity->id);
if (!empty($groups)) {
foreach ($groups as $group) {
$groupinstance = instance::get_group_instance_from_instance($instance, $group->id);
$plugingenerator->create_meeting([
'instanceid' => $groupinstance->get_instance_id(),
'groupid' => $groupinstance->get_group_id(),
]);
}
} else {
$plugingenerator->create_meeting([
'instanceid' => $instance->get_instance_id(),
'groupid' => $instance->get_group_id(),
]);
}
return $instance;
}
}