diff --git a/mod/bigbluebuttonbn/backup/moodle2/backup_bigbluebuttonbn_stepslib.php b/mod/bigbluebuttonbn/backup/moodle2/backup_bigbluebuttonbn_stepslib.php index f943110ed6e..3be1678c89e 100644 --- a/mod/bigbluebuttonbn/backup/moodle2/backup_bigbluebuttonbn_stepslib.php +++ b/mod/bigbluebuttonbn/backup/moodle2/backup_bigbluebuttonbn_stepslib.php @@ -86,6 +86,7 @@ class backup_bigbluebuttonbn_activity_structure_step extends backup_activity_str // Define file annotations. $bigbluebuttonbn->annotate_files('mod_bigbluebuttonbn', 'intro', null); + $this->add_subplugin_structure('bbbext', $bigbluebuttonbn, true); // Return the root element (bigbluebuttonbn), wrapped into standard activity structure. return $this->prepare_activity_structure($bigbluebuttonbn); } diff --git a/mod/bigbluebuttonbn/backup/moodle2/restore_bigbluebuttonbn_stepslib.php b/mod/bigbluebuttonbn/backup/moodle2/restore_bigbluebuttonbn_stepslib.php index 5bb38451017..3d6ca88b56f 100644 --- a/mod/bigbluebuttonbn/backup/moodle2/restore_bigbluebuttonbn_stepslib.php +++ b/mod/bigbluebuttonbn/backup/moodle2/restore_bigbluebuttonbn_stepslib.php @@ -39,9 +39,11 @@ class restore_bigbluebuttonbn_activity_structure_step extends restore_activity_s */ protected function define_structure() { $paths = []; - $paths[] = new restore_path_element('bigbluebuttonbn', '/activity/bigbluebuttonbn'); + $bbb = new restore_path_element('bigbluebuttonbn', '/activity/bigbluebuttonbn'); + $paths[] = $bbb; $paths[] = new restore_path_element('bigbluebuttonbn_logs', '/activity/bigbluebuttonbn/logs/log'); $paths[] = new restore_path_element('bigbluebuttonbn_recordings', '/activity/bigbluebuttonbn/recordings/recording'); + $this->add_subplugin_structure('bbbext', $bbb); // Return the paths wrapped into standard activity structure. return $this->prepare_activity_structure($paths); } diff --git a/mod/bigbluebuttonbn/classes/test/subplugins_test_helper_trait.php b/mod/bigbluebuttonbn/classes/test/subplugins_test_helper_trait.php index 1499487afbc..4c2351fbdd9 100644 --- a/mod/bigbluebuttonbn/classes/test/subplugins_test_helper_trait.php +++ b/mod/bigbluebuttonbn/classes/test/subplugins_test_helper_trait.php @@ -26,6 +26,7 @@ namespace mod_bigbluebuttonbn\test; use core_component; +use core_plugin_manager; use mod_bigbluebuttonbn\extension; use ReflectionClass; @@ -75,5 +76,36 @@ trait subplugins_test_helper_trait { $this->resetDebugging(); // We might have debugging messages here that we need to get rid of. // End of the component loader mock. } + /** + * Uninstall a fake extension plugin + * + * This is intended to behave in most case like a real subplugina and will + * allow most functionalities to be tested. + * + * @param string $pluginname plugin name + * @return void + */ + protected function uninstall_fake_plugin(string $pluginname): void { + // We just need access to fill_all_caches so everything goes back to normal. + // If we don't do this, there are some side effects that will make other test fails + // (such as mod_bigbluebuttonbn\task\upgrade_recordings_task_test::test_upgrade_recordings_imported_basic). + $mockedcomponent = new ReflectionClass(core_component::class); + // Here we reset the plugin caches. + $fillclassmap = $mockedcomponent->getMethod('fill_all_caches'); + $fillclassmap->setAccessible(true); + $fillclassmap->invoke(null); + // Now uninstall the plugin and clean everything up for other tests. + $pluginman = core_plugin_manager::instance(); + $plugininfo = $pluginman->get_plugins(); + foreach ($plugininfo as $type => $plugins) { + foreach ($plugins as $name => $plugin) { + if ($name === $pluginname) { + ob_start(); + uninstall_plugin($type, $name); + ob_end_clean(); + } + } + } + } } diff --git a/mod/bigbluebuttonbn/tests/fixtures/extension/simple/backup/moodle2/backup_bbbext_simple_subplugin.class.php b/mod/bigbluebuttonbn/tests/fixtures/extension/simple/backup/moodle2/backup_bbbext_simple_subplugin.class.php new file mode 100644 index 00000000000..6efd870c2ae --- /dev/null +++ b/mod/bigbluebuttonbn/tests/fixtures/extension/simple/backup/moodle2/backup_bbbext_simple_subplugin.class.php @@ -0,0 +1,55 @@ +. + +/** + * Provides the information for backup. + * + * @package mod_bigbluebuttonbn + * @copyright 2023 onwards, Blindside Networks Inc + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + * @author Laurent David (laurent@call-learning.fr) + */ +class backup_bbbext_simple_subplugin extends backup_subplugin { + + /** + * Returns the subplugin information to attach to submission element. + * + * @return backup_subplugin_element + */ + protected function define_bigbluebuttonbn_subplugin_structure() { + + // Create XML elements. + $subplugin = $this->get_subplugin_element(); + $subpluginwrapper = new backup_nested_element($this->get_recommended_name()); + $subpluginelement = new backup_nested_element( + 'bbbext_simple', + null, + ['newfield', 'completionextraisehandtwice'] + ); + + // Connect XML elements into the tree. + $subplugin->add_child($subpluginwrapper); + $subpluginwrapper->add_child($subpluginelement); + + // Set source to populate the data. + $subpluginelement->set_source_table( + 'bbbext_simple', + ['bigbluebuttonbnid' => backup::VAR_PARENTID] + ); + + return $subplugin; + } +} diff --git a/mod/bigbluebuttonbn/tests/fixtures/extension/simple/backup/moodle2/restore_bbbext_simple_subplugin.class.php b/mod/bigbluebuttonbn/tests/fixtures/extension/simple/backup/moodle2/restore_bbbext_simple_subplugin.class.php new file mode 100644 index 00000000000..1a1b143676e --- /dev/null +++ b/mod/bigbluebuttonbn/tests/fixtures/extension/simple/backup/moodle2/restore_bbbext_simple_subplugin.class.php @@ -0,0 +1,57 @@ +. + +/** + * Provides the information for restore. + * + * + * @package mod_bigbluebuttonbn + * @copyright 2023 onwards, Blindside Networks Inc + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + * @author Laurent David (laurent@call-learning.fr) + */ +class restore_bbbext_simple_subplugin extends restore_subplugin { + /** + * Returns the paths to be handled by the subplugin at workshop level + * + * @return array + */ + protected function define_bigbluebuttonbn_subplugin_structure() { + + $paths = []; + + $elename = $this->get_namefor('bigbluebuttonbn'); + // We used get_recommended_name() so this works. + $elepath = $this->get_pathfor('/bbbext_simple'); + + $paths[] = new restore_path_element($elename, $elepath); + + return $paths; + } + + /** + * Processes one feedback_comments element. + * + * @param mixed $data + */ + public function process_bbbext_simple_bigbluebuttonbn($data) { + global $DB; + + $data = (object) $data; + $data->bigbluebuttonbnid = $this->get_new_parentid('bigbluebuttonbn'); + $DB->insert_record('bbbext_simple', $data); + } +} diff --git a/mod/bigbluebuttonbn/tests/local/extension_test.php b/mod/bigbluebuttonbn/tests/local/extension_test.php index 1211c2e3b4f..ac36caef844 100644 --- a/mod/bigbluebuttonbn/tests/local/extension_test.php +++ b/mod/bigbluebuttonbn/tests/local/extension_test.php @@ -15,10 +15,14 @@ // along with Moodle. If not, see . namespace mod_bigbluebuttonbn\local; +use backup; +use backup_controller; use mod_bigbluebuttonbn\extension; use mod_bigbluebuttonbn\local\extension\mod_instance_helper; use mod_bigbluebuttonbn\test\subplugins_test_helper_trait; use mod_bigbluebuttonbn\test\testcase_helper_trait; +use restore_controller; +use restore_dbops; /** * Extension helper class test @@ -43,6 +47,16 @@ class extension_test extends \advanced_testcase { $this->setup_fake_plugin('simple'); } + + /** + * Setup our fake plugin + * + * @return void + */ + public function tearDown(): void { + $this->uninstall_fake_plugin('simple'); + } + /** * Test for the type_text provider. * @@ -148,6 +162,76 @@ class extension_test extends \advanced_testcase { $this->assertEmpty($additionalvar2); } + /** + * Test backup restore (with extension) + * + * @covers \backup_bigbluebuttonbn_activity_task + */ + public function test_backup_restore(): void { + global $DB, $CFG, $USER; + require_once($CFG->dirroot . '/backup/util/includes/restore_includes.php'); + require_once($CFG->dirroot . '/backup/util/includes/backup_includes.php'); + $this->resetAfterTest(); + $course = $this->get_course(); + [$cm, $cminfo, $bbactivity] = $this->create_instance($course); + $bbactivity->newfield = 4; + extension::update_instance($bbactivity); + + $this->setAdminUser(); + + $CFG->backup_file_logger_level = backup::LOG_NONE; + + // Do backup with default settings. + set_config('backup_general_users', 1, 'backup'); + $bc = new backup_controller(backup::TYPE_1COURSE, $course->id, + backup::FORMAT_MOODLE, backup::INTERACTIVE_NO, backup::MODE_GENERAL, + $USER->id); + $bc->execute_plan(); + $results = $bc->get_results(); + $file = $results['backup_destination']; + $fp = get_file_packer('application/vnd.moodle.backup'); + $filepath = $CFG->dataroot . '/temp/backup/test-restore-course'; + $file->extract_to_pathname($fp, $filepath); + $bc->destroy(); + + // Do restore to new course with default settings. + $newcourseid = restore_dbops::create_new_course( + $course->fullname, $course->shortname . '_2', $course->category); + $rc = new restore_controller('test-restore-course', $newcourseid, + backup::INTERACTIVE_NO, backup::MODE_GENERAL, $USER->id, + backup::TARGET_NEW_COURSE); + $rc->execute_precheck(); + $rc->execute_plan(); + $rc->destroy(); + $cms = get_fast_modinfo($newcourseid)->get_cms(); + $newmoduleid = null; + foreach ($cms as $id => $cm) { + if ($cm->modname == 'bigbluebuttonbn') { + $newmoduleid = $cm->instance; + } + } + // Check instance has been copied. + $this->assertNotNull($newmoduleid); + + // Change the original instance value (this makes sure we are not looking at the same value in the + // original and copy). + $bbactivity->newfield = 5; + extension::update_instance($bbactivity); + + // Now check the copied instance. + $newfieldrecord = $DB->get_record('bbbext_simple', [ + 'bigbluebuttonbnid' => $newmoduleid, + ]); + $this->assertNotNull($newfieldrecord); + $this->assertEquals(4, $newfieldrecord->newfield); + // And the original. + $oldfieldrecord = $DB->get_record('bbbext_simple', [ + 'bigbluebuttonbnid' => $bbactivity->id, + ]); + $this->assertNotNull($oldfieldrecord); + $this->assertEquals(5, $oldfieldrecord->newfield); + } + /** * Data provider for testing get_class_implementing *