<?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/>.
/**
* BBB Library tests class trait.
*
* @package mod_bigbluebuttonbn
* @copyright 2018 - present, Blindside Networks Inc
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @author Laurent David (laurent@call-learning.fr)
*/
namespace mod_bigbluebuttonbn\test;
use context_module;
use mod_bigbluebuttonbn\instance;
use mod_bigbluebuttonbn\local\proxy\recording_proxy;
use mod_bigbluebuttonbn\meeting;
use stdClass;
use testing_data_generator;
use core\plugininfo\mod;
trait testcase_helper_trait {
/** @var testing_data_generator|null */
protected $generator = null;
/** @var object|null */
protected $course = null;
/**
* Convenience function to create an instance of a bigbluebuttonactivty.
*
* @param stdClass|null $course course to add the module to
* @param array $params Array of parameters to pass to the generator
* @param array $options Array of options to pass to the generator
* @return array($context, $cm, $instance) Testable wrapper around the assign class.
*/
protected function create_instance(?stdClass $course = null, array $params = [], array $options = []): array {
// Prior to creating the instance, make sure that the BigBlueButton module is enabled.
$modules = \core_plugin_manager::instance()->get_plugins_of_type('mod');
if (!$modules['bigbluebuttonbn']->is_enabled()) {
mod::enable_plugin('bigbluebuttonbn', true);
}
if (!$course) {
$course = $this->get_course();
}
$params['course'] = $course->id;
$options['visible'] = 1;
$instance = $this->getDataGenerator()->create_module('bigbluebuttonbn', $params, $options);
list($course, $cm) = get_course_and_cm_from_instance($instance, 'bigbluebuttonbn');
$context = context_module::instance($cm->id);
return [$context, $cm, $instance];
}
/**
* Get the matching form data
*
* @param stdClass $bbactivity the current bigbluebutton activity
* @param stdClass|null $course the course or null (taken from $this->get_course() if null)
* @return mixed
*/
protected function get_form_data_from_instance(stdClass $bbactivity, ?stdClass $course = null): object {
global $USER;
if (!$course) {
$course = $this->get_course();
}
$this->setAdminUser();
$bbactivitycm = get_coursemodule_from_instance('bigbluebuttonbn', $bbactivity->id);
list($cm, $context, $module, $data, $cw) = get_moduleinfo_data($bbactivitycm, $course);
$this->setUser($USER);
return $data;
}
/**
* Get or create course if it does not exist
*
* @return stdClass|null
*/
protected function get_course(): stdClass {
if (!$this->course) {
$this->course = $this->getDataGenerator()->create_course(['enablecompletion' => 1]);
}
return $this->course;
}
/**
* Generate a course, several students and several groups
*
* @param stdClass $courserecord
* @param int $numstudents
* @param int $numteachers
* @param int $groupsnum
* @return array
*/
protected function setup_course_students_teachers(stdClass $courserecord, int $numstudents, int $numteachers,
int $groupsnum): array {
global $DB;
$generator = $this->getDataGenerator();
$course = $generator->create_course($courserecord);
$groups = [];
for ($i = 0; $i < $groupsnum; $i++) {
$groups[] = $generator->create_group(['courseid' => $course->id]);
}
$generator->create_group(['courseid' => $course->id]);
$generator->create_group(['courseid' => $course->id]);
$roleids = $DB->get_records_menu('role', null, '', 'shortname, id');
$students = [];
for ($i = 0; $i < $numstudents; $i++) {
$student = $generator->create_user();
$generator->enrol_user($student->id, $course->id, $roleids['student']);
$groupid = $groups[$i % $groupsnum]->id;
groups_add_member($groupid, $student->id);
$students[] = $student;
}
$teachers = [];
for ($i = 0; $i < $numteachers; $i++) {
$teacher = $generator->create_user();
$generator->enrol_user($teacher->id, $course->id, $roleids['teacher']);
$groupid = $groups[$i % $groupsnum]->id;
groups_add_member($groupid, $teacher->id);
$teachers[] = $teacher;
}
$bbactivity = $generator->create_module(
'bigbluebuttonbn',
['course' => $course->id],
['visible' => true]);
get_fast_modinfo(0, 0, true);
return [$course, $groups, $students, $teachers, $bbactivity, $roleids];
}
/**
* This test requires mock server to be present.
*/
protected function initialise_mock_server(): void {
if (!defined('TEST_MOD_BIGBLUEBUTTONBN_MOCK_SERVER')) {
$this->markTestSkipped(
'The TEST_MOD_BIGBLUEBUTTONBN_MOCK_SERVER constant must be defined to run mod_bigbluebuttonbn tests'
);
}
try {
$this->getDataGenerator()->get_plugin_generator('mod_bigbluebuttonbn')->reset_mock();
} catch (\moodle_exception $e) {
$this->markTestSkipped(
'Cannot connect to the mock server for this test. Make sure that TEST_MOD_BIGBLUEBUTTONBN_MOCK_SERVER points
to an active Mock server'
);
}
}
/**
* Create an return an array of recordings
*
* @param instance $instance
* @param array $recordingdata array of recording information
* @param array $additionalmeetingdata
* @return array
*/
protected function create_recordings_for_instance(instance $instance, array $recordingdata = [],
$additionalmeetingdata = []): array {
$recordings = [];
$bbbgenerator = $this->getDataGenerator()->get_plugin_generator('mod_bigbluebuttonbn');
// Create the meetings on the mock server, so like this we can find the recordings.
$meeting = new meeting($instance);
$meeting->update_cache(); // The meeting has just been created but we need to force fetch info from the server.
if (!$meeting->is_running()) {
$additionalmeetingdata = array_merge([
'instanceid' => $instance->get_instance_id(),
'groupid' => $instance->get_group_id()
], $additionalmeetingdata);
$bbbgenerator->create_meeting($additionalmeetingdata);
}
foreach ($recordingdata as $rindex => $data) {
$recordings[] = $bbbgenerator->create_recording(
array_merge([
'bigbluebuttonbnid' => $instance->get_instance_id(),
'groupid' => $instance->get_group_id()
], $data)
);
}
return $recordings;
}
/**
* Create an activity which includes a set of recordings.
*
* @param stdClass $course
* @param int $type
* @param array $recordingdata array of recording information
* @param int $groupid
* @return array
*/
protected function create_activity_with_recordings(stdClass $course, int $type, array $recordingdata, int $groupid = 0): array {
$generator = $this->getDataGenerator()->get_plugin_generator('mod_bigbluebuttonbn');
$activity = $generator->create_instance([
'course' => $course->id,
'type' => $type
]);
$instance = instance::get_from_instanceid($activity->id);
$instance->set_group_id($groupid);
$recordings = $this->create_recordings_for_instance($instance, $recordingdata);
return [
'course' => $course,
'activity' => $activity,
'recordings' => $recordings,
];
}
/**
* Create a course, users and recording from dataset given in an array form
*
* @param array $dataset
* @return mixed
*/
protected function create_from_dataset(array $dataset) {
list('type' => $type, 'recordingsdata' => $recordingsdata, 'groups' => $groups,
'users' => $users) = $dataset;
$plugingenerator = $this->getDataGenerator()->get_plugin_generator('mod_bigbluebuttonbn');
$coursedata = empty($groups) ? [] : ['groupmodeforce' => true, 'groupmode' => $dataset['coursemode'] ?? VISIBLEGROUPS];
$this->course = $this->getDataGenerator()->create_course($coursedata);
foreach ($users as $userdata) {
$this->getDataGenerator()->create_and_enrol($this->course, $userdata['role'], ['username' => $userdata['username']]);
}
if ($groups) {
foreach ($groups as $groupname => $students) {
$group = $this->getDataGenerator()->create_group(['name' => $groupname, 'courseid' => $this->course->id]);
foreach ($students as $username) {
$user = \core_user::get_user_by_username($username);
$this->getDataGenerator()->create_group_member(['userid' => $user->id, 'groupid' => $group->id]);
}
}
}
$instancesettings = [
'course' => $this->course->id,
'type' => $type,
'name' => 'Example',
];
if (!empty($dataset['additionalsettings'])) {
$instancesettings = array_merge($instancesettings, $dataset['additionalsettings']);
}
$activity = $plugingenerator->create_instance($instancesettings);
$instance = instance::get_from_instanceid($activity->id);
foreach ($recordingsdata as $groupname => $recordings) {
if ($groups) {
$groupid = groups_get_group_by_name($this->course->id, $groupname);
$instance->set_group_id($groupid);
}
$this->create_recordings_for_instance($instance, $recordings);
}
return $activity->id;
}
/**
* Create the legacy log entries for this task.
*
* @param instance $instance
* @param int $userid
* @param int $count
* @param bool $importedrecordings
* @param bool $withremoterecordings create recording on the mock server ?
* @return array
*/
< protected function create_legacy_log_entries(
> protected function create_log_entries(
instance $instance,
int $userid,
int $count = 30,
bool $importedrecordings = false,
bool $withremoterecordings = true
): array {
// Create log entries for each (30 for the ungrouped, 30 for the grouped).
$baselogdata = [
'courseid' => $instance->get_course_id(),
'userid' => $userid,
'log' => $importedrecordings ? 'Import' : 'Create',
'meta' => json_encode(['record' => true]),
'imported' => $importedrecordings,
];
$plugingenerator = $this->getDataGenerator()->get_plugin_generator('mod_bigbluebuttonbn');
for ($i = 0; $i < $count; $i++) {
if ($withremoterecordings) {
// Create a recording.
$starttime = time() - random_int(HOURSECS, WEEKSECS);
$recording = $plugingenerator->create_recording([
'bigbluebuttonbnid' => $instance->get_instance_id(),
'groupid' => $instance->get_group_id(),
'starttime' => $starttime,
'endtime' => $starttime + HOURSECS,
], true); // Create them on the server only.
$baselogdata['meetingid'] = $instance->get_meeting_id();
if ($importedrecordings) {
// Fetch the data.
$data = recording_proxy::fetch_recordings([$recording->recordingid]);
$data = end($data);
if ($data) {
$metaonly = array_filter($data, function($key) {
return strstr($key, 'meta_');
}, ARRAY_FILTER_USE_KEY);
} else {
$data = [];
}
$baselogdata['meta'] = json_encode(array_merge([
'recording' => array_diff_key($data, $metaonly),
], $metaonly));
} else {
$baselogdata['meta'] = json_encode((object) ['record' => true]);
}
}
// Insert the legacy log entry.
$logs[] = $plugingenerator->create_log(array_merge($baselogdata, [
'bigbluebuttonbnid' => $instance->get_instance_id(),
'timecreated' => time() - random_int(HOURSECS, WEEKSECS) + (HOURSECS * $i),
]));
}
return $logs;
}
}