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 namespace qbank_comment; 18 19 defined('MOODLE_INTERNAL') || die(); 20 21 global $CFG; 22 require_once($CFG->dirroot . '/backup/util/includes/backup_includes.php'); 23 require_once($CFG->dirroot . '/backup/util/includes/restore_includes.php'); 24 require_once($CFG->dirroot. '/comment/lib.php'); 25 26 /** 27 * Question comment backup and restore unit tests. 28 * 29 * @package qbank_comment 30 * @copyright 2021 Catalyst IT Australia Pty Ltd 31 * @author Matt Porritt <mattp@catalyst-au.net> 32 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 33 */ 34 class backup_test extends \advanced_testcase { 35 36 /** 37 * @var array Data object for generating a question. 38 */ 39 protected $question1data; 40 41 /** 42 * @var array Data object for generating a question. 43 */ 44 protected $question2data; 45 46 /** 47 * @var component_generator_base Question Generator. 48 */ 49 protected $qgen; 50 51 /** 52 * @var core_course_category Course category. 53 */ 54 protected $category; 55 56 /** 57 * @var stdClass Course object. 58 */ 59 protected $course; 60 61 /** 62 * Set up 63 */ 64 protected function setUp(): void { 65 parent::setUp(); 66 $this->resetAfterTest(); 67 $this->setAdminUser(); 68 69 // Set up custom fields. 70 $data = new \stdClass(); 71 $data->component = 'qbank_comment'; 72 $data->area = 'question'; 73 74 // Question initial set up. 75 $this->category = $this->getDataGenerator()->create_category(); 76 $this->course = $this->getDataGenerator()->create_course(['category' => $this->category->id]); 77 $context = \context_coursecat::instance($this->category->id); 78 $this->qgen = $this->getDataGenerator()->get_plugin_generator('core_question'); 79 $qcat = $this->qgen->create_question_category(['contextid' => $context->id]); 80 81 $this->question1data = ['category' => $qcat->id, 'idnumber' => 'q1']; 82 $this->question2data = ['category' => $qcat->id, 'idnumber' => 'q2']; 83 } 84 85 /** 86 * Makes a backup of the course. 87 * 88 * @param \stdClass $course The course object. 89 * @return string Unique identifier for this backup. 90 */ 91 protected function backup_course(\stdClass $course): string { 92 global $CFG, $USER; 93 94 // Turn off file logging, otherwise it can't delete the file (Windows). 95 $CFG->backup_file_logger_level = \backup::LOG_NONE; 96 97 // Do backup with default settings. MODE_IMPORT means it will just 98 // create the directory and not zip it. 99 $bc = new \backup_controller(\backup::TYPE_1COURSE, $course->id, 100 \backup::FORMAT_MOODLE, \backup::INTERACTIVE_NO, \backup::MODE_IMPORT, 101 $USER->id); 102 $backupid = $bc->get_backupid(); 103 $bc->execute_plan(); 104 $bc->destroy(); 105 106 return $backupid; 107 } 108 109 /** 110 * Restores a backup that has been made earlier. 111 * 112 * @param string $backupid The unique identifier of the backup. 113 * @param string $fullname Full name of the new course that is going to be created. 114 * @param string $shortname Short name of the new course that is going to be created. 115 * @param int $categoryid The course category the backup is going to be restored in. 116 * @return int The new course id. 117 */ 118 protected function restore_course(string $backupid, string $fullname, string $shortname, int $categoryid): int { 119 global $CFG, $USER; 120 121 // Turn off file logging, otherwise it can't delete the file (Windows). 122 $CFG->backup_file_logger_level = \backup::LOG_NONE; 123 124 // Do restore to new course with default settings. 125 $newcourseid = \restore_dbops::create_new_course($fullname, $shortname, $categoryid); 126 $rc = new \restore_controller($backupid, $newcourseid, 127 \backup::INTERACTIVE_NO, \backup::MODE_GENERAL, $USER->id, 128 \backup::TARGET_NEW_COURSE); 129 130 $rc->execute_precheck(); 131 $rc->execute_plan(); 132 $rc->destroy(); 133 134 return $newcourseid; 135 } 136 137 /** 138 * Test comments attached to questions persist 139 * across the backup and restore process. 140 */ 141 public function test_backup_restore() { 142 global $DB, $CFG; 143 require_once($CFG->dirroot . '/comment/lib.php'); 144 $this->resetAfterTest(); 145 $this->setAdminUser(); 146 147 $courseshortname = $this->course->shortname; 148 $coursefullname = $this->course->fullname; 149 150 // Create 2 questions. 151 $question1 = $this->qgen->create_question('shortanswer', null, $this->question1data); 152 $question2 = $this->qgen->create_question('shortanswer', null, $this->question2data); 153 154 // Add comments to the questions. 155 $args = new \stdClass; 156 $args->context = \context_system::instance(); 157 $args->course = $this->course; 158 $args->area = 'question'; 159 $args->itemid = $question1->id; 160 $args->component = 'qbank_comment'; 161 $args->linktext = get_string('commentheader', 'qbank_comment'); 162 $args->notoggle = true; 163 $args->autostart = true; 164 $args->displaycancel = false; 165 166 // Two comments for question 1. 167 $commentobj1 = new \comment($args); 168 $commentobj1->add('new \comment for question 1 _ 1'); 169 $comment1 = $commentobj1->add('new \comment for question 1 _ 2'); 170 171 // One comment for question 2. 172 $args->itemid = $question2->id; 173 $commentobj2 = new \comment($args); 174 $comment2 = $commentobj2->add('new \comment for question 2'); 175 176 // Create a quiz and the questions to that. 177 $quiz = $this->getDataGenerator()->create_module( 178 'quiz', ['course' => $this->course->id, 'name' => 'restored_quiz']); 179 quiz_add_quiz_question($question1->id, $quiz); 180 quiz_add_quiz_question($question2->id, $quiz); 181 182 // Backup the course. 183 $backupid = $this->backup_course($this->course); 184 185 // Now delete everything. 186 delete_course($this->course, false); 187 question_delete_question($question1->id); 188 question_delete_question($question2->id); 189 190 // Check the comment data for the questions has also gone. 191 $DB->record_exists('comments', ['id' => $comment1->id]); 192 $this->assertFalse($DB->record_exists('comments', ['id' => $comment1->id])); 193 $this->assertFalse($DB->record_exists('comments', ['id' => $comment2->id])); 194 195 // Restore the backup we had made earlier into a new course. 196 $newcategory = $this->getDataGenerator()->create_category(); 197 $this->restore_course($backupid, $coursefullname, $courseshortname . '_2', $newcategory->id); 198 199 // The questions and their associated comments should have been restored. 200 $sql = 201 'SELECT q.* 202 FROM {question} q 203 JOIN {question_versions} qv ON qv.questionid = q.id 204 JOIN {question_bank_entries} qbe ON qbe.id = qv.questionbankentryid 205 WHERE qbe.idnumber = ?'; 206 $newquestion1 = $DB->get_record_sql($sql, ['idnumber' => 'q1']); 207 $args->itemid = $newquestion1->id; 208 $commentobj = new \comment($args); 209 $this->assertEquals($commentobj->count(), 2); 210 211 $newquestion2 = $DB->get_record_sql($sql, ['idnumber' => 'q2']); 212 $args->itemid = $newquestion2->id; 213 $commentobj = new \comment($args); 214 $this->assertEquals($commentobj->count(), 1); 215 } 216 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body